2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 package com
.intellij
.psi
.impl
;
22 import com
.intellij
.ide
.fileTemplates
.FileTemplate
;
23 import com
.intellij
.ide
.fileTemplates
.FileTemplateManager
;
24 import com
.intellij
.ide
.fileTemplates
.JavaTemplateUtil
;
25 import com
.intellij
.openapi
.diagnostic
.Logger
;
26 import com
.intellij
.openapi
.fileTypes
.FileType
;
27 import com
.intellij
.openapi
.fileTypes
.StdFileTypes
;
28 import com
.intellij
.openapi
.progress
.ProcessCanceledException
;
29 import com
.intellij
.openapi
.roots
.LanguageLevelProjectExtension
;
30 import com
.intellij
.pom
.java
.LanguageLevel
;
31 import com
.intellij
.psi
.*;
32 import com
.intellij
.psi
.impl
.source
.DummyHolderFactory
;
33 import com
.intellij
.psi
.impl
.source
.SourceTreeToPsiMap
;
34 import com
.intellij
.psi
.impl
.source
.parsing
.DeclarationParsing
;
35 import com
.intellij
.psi
.impl
.source
.parsing
.ExpressionParsing
;
36 import com
.intellij
.psi
.impl
.source
.parsing
.JavaParsingContext
;
37 import com
.intellij
.psi
.impl
.source
.parsing
.Parsing
;
38 import com
.intellij
.psi
.impl
.source
.tree
.CompositeElement
;
39 import com
.intellij
.psi
.impl
.source
.tree
.FileElement
;
40 import com
.intellij
.psi
.impl
.source
.tree
.JavaElementType
;
41 import com
.intellij
.psi
.impl
.source
.tree
.TreeElement
;
42 import com
.intellij
.psi
.javadoc
.PsiDocComment
;
43 import com
.intellij
.psi
.javadoc
.PsiDocTag
;
44 import com
.intellij
.psi
.util
.PsiUtil
;
45 import com
.intellij
.util
.IncorrectOperationException
;
46 import com
.intellij
.util
.containers
.HashMap
;
47 import org
.jetbrains
.annotations
.NonNls
;
48 import org
.jetbrains
.annotations
.NotNull
;
51 import java
.util
.Properties
;
53 public class PsiJavaParserFacadeImpl
extends PsiParserFacadeImpl
implements PsiJavaParserFacade
{
54 private static final Logger LOG
= Logger
.getInstance("#com.intellij.psi.impl.PsiJavaParserFacadeImpl");
56 protected static final Map
<String
, PsiPrimitiveType
> ourPrimitiveTypesMap
= new HashMap
<String
, PsiPrimitiveType
>();
57 protected PsiJavaFile myDummyJavaFile
;
59 public PsiJavaParserFacadeImpl(PsiManagerEx manager
) {
64 public PsiAnnotation
createAnnotationFromText(@NotNull String annotationText
, PsiElement context
) throws IncorrectOperationException
{
65 final FileElement holderElement
= DummyHolderFactory
.createHolder(myManager
, context
).getTreeElement();
66 CompositeElement annotationElement
= getJavaParsingContext(holderElement
).getDeclarationParsing().parseAnnotationFromText(myManager
, annotationText
, getLanguageLevel(context
));
67 if (annotationElement
== null || annotationElement
.getElementType() != JavaElementType
.ANNOTATION
) {
68 throw new IncorrectOperationException("Incorrect annotation \"" + annotationText
+ "\".");
70 holderElement
.rawAddChildren(annotationElement
);
71 return (PsiAnnotation
)SourceTreeToPsiMap
.treeElementToPsi(annotationElement
);
74 private LanguageLevel
getLanguageLevel(final PsiElement context
) {
75 if (context
== null) {
76 return LanguageLevelProjectExtension
.getInstance(myManager
.getProject()).getLanguageLevel();
78 return PsiUtil
.getLanguageLevel(context
);
82 public PsiDocTag
createDocTagFromText(@NotNull String docTagText
, PsiElement context
) throws IncorrectOperationException
{
83 StringBuilder buffer
= new StringBuilder();
84 buffer
.append("/**\n");
85 buffer
.append(docTagText
);
86 buffer
.append("\n */");
87 PsiDocComment comment
= createDocCommentFromText(buffer
.toString(), context
);
88 return comment
.getTags()[0];
92 public PsiDocComment
createDocCommentFromText(@NotNull String docCommentText
, PsiElement context
) throws IncorrectOperationException
{
93 @NonNls StringBuilder buffer
= new StringBuilder();
94 buffer
.append(docCommentText
);
95 buffer
.append("void m();");
96 final PsiMethod method
= createMethodFromText(buffer
.toString(), null);
97 return method
.getDocComment();
101 public PsiClass
createClassFromText(@NotNull String body
, PsiElement context
) throws IncorrectOperationException
{
102 @NonNls String fileText
= "class _Dummy_ { " + body
+ " }";
103 PsiJavaFile aFile
= createDummyJavaFile(fileText
);
104 PsiClass
[] classes
= aFile
.getClasses();
105 if (classes
.length
!= 1) {
106 throw new IncorrectOperationException("Incorrect class \"" + body
+ "\".");
112 public PsiField
createFieldFromText(@NotNull String text
, PsiElement context
) throws IncorrectOperationException
{
113 final FileElement holderElement
= DummyHolderFactory
.createHolder(myManager
, context
).getTreeElement();
114 TreeElement decl
= getJavaParsingContext(holderElement
).getDeclarationParsing().parseDeclarationText(myManager
, LanguageLevelProjectExtension
115 .getInstance(myManager
.getProject()).getLanguageLevel(), text
, DeclarationParsing
.Context
.CLASS_CONTEXT
);
116 if (decl
== null || decl
.getElementType() != JavaElementType
.FIELD
) {
117 throw new IncorrectOperationException("Incorrect field \"" + text
+ "\".");
119 holderElement
.rawAddChildren(decl
);
120 return (PsiField
)SourceTreeToPsiMap
.treeElementToPsi(decl
);
123 protected JavaParsingContext
getJavaParsingContext (FileElement holderElement
) {
124 return new JavaParsingContext(holderElement
.getCharTable(), LanguageLevelProjectExtension
.getInstance(myManager
.getProject()).getLanguageLevel());
127 private static JavaParsingContext
getJavaParsingContext (FileElement holderElement
, LanguageLevel languageLevel
) {
128 return new JavaParsingContext(holderElement
.getCharTable(), languageLevel
);
132 public PsiMethod
createMethodFromText(@NotNull String text
, PsiElement context
, LanguageLevel level
) throws IncorrectOperationException
{
133 final FileElement holderElement
= DummyHolderFactory
.createHolder(myManager
, context
).getTreeElement();
134 TreeElement decl
= getJavaParsingContext(holderElement
, level
).getDeclarationParsing().parseDeclarationText(myManager
, level
, text
,
135 DeclarationParsing
.Context
.CLASS_CONTEXT
);
136 if (decl
== null || decl
.getElementType() != JavaElementType
.METHOD
) {
137 throw new IncorrectOperationException("Incorrect method \"" + text
+ "\".");
139 holderElement
.rawAddChildren(decl
);
140 return (PsiMethod
)SourceTreeToPsiMap
.treeElementToPsi(decl
);
144 public final PsiMethod
createMethodFromText(@NotNull String text
, PsiElement context
) throws IncorrectOperationException
{
145 return createMethodFromText(text
, context
, LanguageLevelProjectExtension
.getInstance(myManager
.getProject()).getLanguageLevel());
149 public PsiParameter
createParameterFromText(@NotNull String text
, PsiElement context
) throws IncorrectOperationException
{
150 final FileElement holderElement
= DummyHolderFactory
.createHolder(myManager
, context
).getTreeElement();
151 CompositeElement param
= getJavaParsingContext(holderElement
).getDeclarationParsing().parseParameterText(text
);
153 throw new IncorrectOperationException("Incorrect parameter \"" + text
+ "\".");
155 holderElement
.rawAddChildren(param
);
156 return (PsiParameter
)SourceTreeToPsiMap
.treeElementToPsi(param
);
160 public PsiType
createTypeFromText(@NotNull String text
, PsiElement context
) throws IncorrectOperationException
{
161 return createTypeInner(text
, context
, false);
164 protected PsiType
createTypeInner(final String text
, final PsiElement context
, boolean markAsCopy
) throws IncorrectOperationException
{
165 PsiPrimitiveType primitiveType
= ourPrimitiveTypesMap
.get(text
);
166 if (primitiveType
!= null) return primitiveType
;
167 final FileElement holderElement
= DummyHolderFactory
.createHolder(myManager
, context
).getTreeElement();
168 CompositeElement typeElement
= Parsing
.parseTypeText(myManager
, text
, 0, text
.length(), holderElement
.getCharTable());
169 if (typeElement
== null) {
170 throw new IncorrectOperationException("Incorrect type \"" + text
+ "\"");
172 holderElement
.rawAddChildren(typeElement
);
174 holderElement
.acceptTree(new GeneratedMarkerVisitor());
176 PsiTypeElement psiTypeElement
= (PsiTypeElement
)SourceTreeToPsiMap
.treeElementToPsi(typeElement
);
177 if (psiTypeElement
== null) {
178 throw new IncorrectOperationException("PSI is null for element "+typeElement
);
180 return psiTypeElement
.getType();
184 public PsiCodeBlock
createCodeBlockFromText(@NotNull String text
, PsiElement context
) throws IncorrectOperationException
{
185 final FileElement holderElement
= DummyHolderFactory
.createHolder(myManager
, context
).getTreeElement();
186 CompositeElement treeElement
= getJavaParsingContext(holderElement
).getStatementParsing().parseCodeBlockText(myManager
, text
);
187 if (treeElement
== null) {
188 throw new IncorrectOperationException("Incorrect code block \"" + text
+ "\".");
190 holderElement
.rawAddChildren(treeElement
);
191 return (PsiCodeBlock
)SourceTreeToPsiMap
.treeElementToPsi(treeElement
);
195 public PsiStatement
createStatementFromText(@NotNull String text
, PsiElement context
) throws IncorrectOperationException
{
196 final FileElement treeHolder
= DummyHolderFactory
.createHolder(myManager
, context
).getTreeElement();
197 TreeElement treeElement
= getJavaParsingContext(treeHolder
).getStatementParsing().parseStatementText(text
);
198 if (treeElement
== null) {
199 throw new IncorrectOperationException("Incorrect statement \"" + text
+ "\".");
201 treeHolder
.rawAddChildren(treeElement
);
202 return (PsiStatement
)SourceTreeToPsiMap
.treeElementToPsi(treeElement
);
206 public PsiExpression
createExpressionFromText(@NotNull String text
, PsiElement context
) throws IncorrectOperationException
{
207 final FileElement treeHolder
= DummyHolderFactory
.createHolder(myManager
, context
).getTreeElement();
208 final CompositeElement treeElement
= ExpressionParsing
.parseExpressionText(myManager
, text
, 0,
209 text
.length(), treeHolder
.getCharTable());
210 if (treeElement
== null) {
211 throw new IncorrectOperationException("Incorrect expression \"" + text
+ "\".");
213 treeHolder
.rawAddChildren(treeElement
);
214 return (PsiExpression
)SourceTreeToPsiMap
.treeElementToPsi(treeElement
);
217 protected PsiJavaFile
createDummyJavaFile(String text
) {
218 String ext
= StdFileTypes
.JAVA
.getDefaultExtension();
219 @NonNls String fileName
= "_Dummy_." + ext
;
220 FileType type
= StdFileTypes
.JAVA
;
222 return (PsiJavaFile
)PsiFileFactory
.getInstance(myManager
.getProject()).createFileFromText(type
, fileName
, text
, 0, text
.length());
226 public PsiTypeParameter
createTypeParameterFromText(@NotNull String text
, PsiElement context
)
227 throws IncorrectOperationException
{
228 final FileElement holderElement
= DummyHolderFactory
.createHolder(myManager
, context
).getTreeElement();
229 TreeElement treeElement
= getJavaParsingContext(holderElement
).getDeclarationParsing().parseTypeParameterText(text
);
230 if (treeElement
== null) {
231 throw new IncorrectOperationException("Incorrect type parameter \"" + text
+ "\"");
233 holderElement
.rawAddChildren(treeElement
);
234 return (PsiTypeParameter
)SourceTreeToPsiMap
.treeElementToPsi(treeElement
);
238 public PsiComment
createCommentFromText(@NotNull String text
, PsiElement context
) throws IncorrectOperationException
{
239 PsiJavaFile aFile
= createDummyJavaFile(text
);
240 PsiElement
[] children
= aFile
.getChildren();
241 for (PsiElement aChildren
: children
) {
242 if (aChildren
instanceof PsiComment
) {
243 if (!aChildren
.getText().equals(text
)) {
244 throw new IncorrectOperationException("Incorrect comment \"" + text
+ "\".");
246 PsiComment comment
= (PsiComment
)aChildren
;
247 DummyHolderFactory
.createHolder(myManager
, (TreeElement
)SourceTreeToPsiMap
.psiElementToTree(comment
), context
);
251 throw new IncorrectOperationException("Incorrect comment \"" + text
+ "\".");
255 public PsiEnumConstant
createEnumConstantFromText(@NotNull String text
, PsiElement context
) throws IncorrectOperationException
{
256 final FileElement holderElement
= DummyHolderFactory
.createHolder(myManager
, context
).getTreeElement();
257 TreeElement decl
= getJavaParsingContext(holderElement
).getDeclarationParsing().parseEnumConstantText(text
);
258 if (decl
== null || decl
.getElementType() != JavaElementType
.ENUM_CONSTANT
) {
259 throw new IncorrectOperationException("Incorrect enum constant text \"" + text
+ "\".");
261 holderElement
.rawAddChildren(decl
);
262 return (PsiEnumConstant
)SourceTreeToPsiMap
.treeElementToPsi(decl
);
266 public PsiCatchSection
createCatchSection(@NotNull PsiClassType exceptionType
,
267 @NotNull String exceptionName
,
268 PsiElement context
) throws IncorrectOperationException
{
269 @NonNls StringBuilder buffer
= new StringBuilder();
270 buffer
.append("catch (");
271 buffer
.append(exceptionType
.getCanonicalText());
272 buffer
.append(" ").append(exceptionName
).append("){}");
273 String catchSectionText
= buffer
.toString();
274 final FileElement holderElement
= DummyHolderFactory
.createHolder(myManager
, context
).getTreeElement();
275 TreeElement catchSection
= getJavaParsingContext(holderElement
).getStatementParsing().parseCatchSectionText(catchSectionText
);
276 LOG
.assertTrue(catchSection
!= null && catchSection
.getElementType() == JavaElementType
.CATCH_SECTION
);
277 holderElement
.rawAddChildren(catchSection
);
278 PsiCatchSection psiCatchSection
= (PsiCatchSection
)SourceTreeToPsiMap
.treeElementToPsi(catchSection
);
280 setupCatchBlock(exceptionName
, context
, psiCatchSection
);
281 return (PsiCatchSection
)myManager
.getCodeStyleManager().reformat(psiCatchSection
);
284 private void setupCatchBlock(String exceptionName
, PsiElement context
, PsiCatchSection psiCatchSection
)
285 throws IncorrectOperationException
{
286 FileTemplate catchBodyTemplate
= FileTemplateManager
.getInstance().getCodeTemplate(JavaTemplateUtil
.TEMPLATE_CATCH_BODY
);
287 LOG
.assertTrue(catchBodyTemplate
!= null);
289 Properties props
= new Properties();
290 props
.setProperty(FileTemplate
.ATTRIBUTE_EXCEPTION
, exceptionName
);
291 if (context
!= null && context
.isPhysical()) {
292 PsiDirectory directory
= context
.getContainingFile().getContainingDirectory();
293 if (directory
!= null) {
294 JavaTemplateUtil
.setPackageNameAttribute(props
, directory
);
297 PsiCodeBlock codeBlockFromText
;
299 String catchBody
= catchBodyTemplate
.getText(props
);
300 codeBlockFromText
= createCodeBlockFromText("{\n" + catchBody
+ "\n}", null);
302 catch (ProcessCanceledException ce
) {
305 catch (Exception e
) {
306 throw new IncorrectOperationException("Incorrect file template",e
);
308 psiCatchSection
.getCatchBlock().replace(codeBlockFromText
);
311 public PsiType
createPrimitiveType(@NotNull String text
, @NotNull PsiAnnotation
[] annotations
) {
312 if (annotations
.length
== 0) {
313 return PsiElementFactoryImpl
.getPrimitiveType(text
);//todo
315 return new PsiPrimitiveType(text
, annotations
);