| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.jetbrains.android.inspections.lint; |
| |
| import com.android.annotations.NonNull; |
| import com.android.annotations.Nullable; |
| import com.android.annotations.VisibleForTesting; |
| import com.google.common.base.Splitter; |
| import com.intellij.openapi.application.Application; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.progress.ProcessCanceledException; |
| import com.intellij.openapi.util.Computable; |
| import com.intellij.openapi.util.TextRange; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.psi.*; |
| import com.intellij.psi.impl.source.tree.JavaElementType; |
| import com.intellij.psi.tree.IElementType; |
| import lombok.ast.*; |
| |
| import java.util.Iterator; |
| |
| /** |
| * Converter which takes a PSI hierarchy for a Java file, and creates a corresponding |
| * Lombok AST tree. |
| * <p> |
| * NOTE: The tree may not be semantically equivalent yet; this converter only attempts |
| * to make the AST correct as far as Lint cares (meaning that it only worries about |
| * the details Lint cares about.) |
| * |
| * This is just a one way conversion. For Lombok AST they've made it two way (since |
| * Lombok needs it) and they perform completeness tests by running the AST in both directions |
| * and comparing the before and after results to make sure it retains the shape. |
| * <p> |
| * The following parts of the AST conversion are known not to be complete/correct: |
| * <ul> |
| * <li> Generic type parameters. Type parameters, such as {@code class Foo<K,V>} |
| * and {@code Collections.<String>emptyList()} are just erased. |
| * <li> Varargs parameters are not preserved as varargs, but get turned into |
| * arrays (e.g. {@code foo(String... args)} becomes {@code foo(String[] args)} |
| * <li> Not all modifiers ({@code volatile}, {@code strictfp}, etc are preserved</li> |
| * <li> Javadoc comment nodes are not converted</li> |
| * <li> Many position are missing (for example for modifiers) or incomplete |
| * (for example for type references, where the overall type reference |
| * has positions but the individual parts do not)</li> |
| * </ul> |
| * |
| * To handle positions specifically I'd like to add a new interface to the Lombok AST |
| * where position information (as well as type resolution) can be performed |
| * lazily, by stashing a reference to the PSI element and adding a location manager |
| * (and a type manager) interface for the nodes to call back to a resolver |
| * which looks up the corresponding PSI element and provides the necessary data. |
| */ |
| public class LombokPsiConverter { |
| /** |
| * If true, insert fully qualified types even when not |
| * present in the source, to make lint not have to worry |
| * about checking imports etc |
| */ |
| private static final boolean EXPAND_TYPES = false; |
| |
| private static final Splitter DOT_SPLITTER = Splitter.on('.').omitEmptyStrings(); |
| |
| private static final PositionFactory POSITION_FACTORY = new PositionFactory() { |
| @Override |
| @Nullable |
| public Position getPosition(@NonNull final Node node) { |
| Application application = ApplicationManager.getApplication(); |
| if (application.isReadAccessAllowed()) { |
| return getPositionImmediate(node); |
| } |
| return application.runReadAction(new Computable<Position>() { |
| @Override |
| @Nullable |
| public Position compute() { |
| return getPositionImmediate(node); |
| } |
| }); |
| } |
| |
| @Nullable |
| private Position getPositionImmediate(@NonNull Node node) { |
| Object nativeNode = node.getNativeNode(); |
| if (nativeNode != null) { |
| PsiElement element = (PsiElement)nativeNode; |
| // Note: We have to use getTextRange() rather than element.getTextOffset() here |
| // because the offsets aren't just the same as the individual getTextRange() values; |
| // in particular, for method declarations etc getTextOffset will point to the |
| // type signature, excluding modifiers, and for selects, it will point to the last |
| // identifier rather than the whole qualified expression -- whereas getTextRange() |
| // gives us what we want. |
| TextRange textRange = element.getTextRange(); |
| int start = textRange.getStartOffset(); |
| int end = textRange.getEndOffset(); |
| |
| // TODO: Compute lbrace/rbrace for classes lazily! |
| //if (element instanceof PsiClass) { |
| // PsiElement lBrace = psiClass.getLBrace(); |
| // PsiElement rBrace = psiClass.getRBrace(); |
| // if (lBrace != null && rBrace != null) { |
| // int start = lBrace.getTextOffset(); |
| // int end = rBrace.getTextOffset() + 1; |
| // body.setPosition(new Position(start, end)); |
| // } |
| //} |
| |
| PsiElement curr = element; |
| while (curr != null) { |
| if (curr instanceof PsiQualifiedReference) { |
| PsiQualifiedReference p = (PsiQualifiedReference)curr; |
| PsiElement qualifier = p.getQualifier(); |
| if (qualifier != null) { |
| start = Math.min(start, qualifier.getTextOffset()); |
| } |
| curr = qualifier; |
| } else if (curr instanceof PsiQualifiedExpression) { |
| PsiQualifiedExpression p = (PsiQualifiedExpression)curr; |
| PsiElement qualifier = p.getQualifier(); |
| if (qualifier != null) { |
| start = Math.min(start, qualifier.getTextOffset()); |
| } |
| curr = qualifier; |
| } else { |
| break; |
| } |
| } |
| |
| return new Position(start, end); |
| } else { |
| // We don't have native node hooks on every single node, |
| // but we can search up for a node, and attempt to use it instead |
| // along with a search for the corresponding item |
| Node n = node; |
| while (n != null) { |
| nativeNode = n.getNativeNode(); |
| if (nativeNode != null) { |
| PsiElement element = (PsiElement)nativeNode; |
| TextRange textRange = element.getTextRange(); |
| int start = textRange.getStartOffset(); |
| int end = textRange.getEndOffset(); |
| |
| String substring; |
| if (node instanceof Identifier) { |
| substring = ((Identifier) node).astValue(); |
| } else if (node instanceof TypeReference) { |
| substring = ((TypeReference) node).getTypeName(); |
| } else if (node instanceof KeywordModifier) { |
| substring = ((KeywordModifier) node).astName(); |
| } else if (node instanceof TypeReferencePart) { |
| substring = ((TypeReferencePart) node).getTypeName(); |
| } else { |
| substring = node.toString(); |
| } |
| if (substring != null) { |
| int delta = element.getText().indexOf(substring); |
| if (delta != -1) { |
| start += delta; |
| end = start + substring.length(); |
| } |
| } |
| |
| return new Position(start, end); |
| } |
| n = n.getParent(); |
| } |
| } |
| |
| return null; |
| } |
| }; |
| |
| private LombokPsiConverter() { |
| } |
| |
| /** |
| * Convert the given {@link PsiJavaFile} to a Lombok AST {@link Node} tree |
| * |
| * @param javaFile the file to be converted |
| * @return a corresponding Lombok AST tree |
| */ |
| @Nullable |
| public static CompilationUnit convert(@NonNull PsiJavaFile javaFile) { |
| try { |
| return toCompilationUnit(javaFile); |
| } catch (ProcessCanceledException e) { |
| // Ignore: common occurrence, e.g. we're running lint as part of an editor background |
| // and while lint is running the user switches files: the inspections framework will |
| // then cancel the process from within the PSI machinery (which asks the progress manager |
| // periodically whether the operation is cancelled) and we find ourselves here |
| return null; |
| } catch (Exception e) { |
| String path = javaFile.getName(); |
| VirtualFile virtualFile = javaFile.getVirtualFile(); |
| if (virtualFile != null) { |
| path = virtualFile.getPath(); |
| } |
| throw new RuntimeException("Could not convert file " + path, e); |
| } |
| } |
| |
| public static Node toNode(@NonNull PsiElement element) { |
| if (element instanceof PsiClass) { |
| return toTypeDeclaration((PsiClass)element); |
| } |
| if (element instanceof PsiMethod) { |
| PsiMethod method = (PsiMethod)element; |
| if (method.isConstructor()) { |
| return toConstructorDeclaration(method); |
| } else { |
| return toMethodDeclaration(method); |
| } |
| } |
| if (element instanceof PsiField) { |
| return toField((PsiField) element); |
| } |
| if (element instanceof PsiVariable) { |
| return toVariableDeclaration((PsiVariable)element); |
| } |
| if (element instanceof PsiIdentifier) { |
| return toIdentifier((PsiIdentifier)element); |
| } |
| if (element instanceof PsiType) { |
| return toTypeReference((PsiType)element); |
| } |
| if (element instanceof PsiJavaFile) { |
| return toCompilationUnit(((PsiJavaFile)element)); |
| } |
| throw new UnsupportedOperationException("Converting element of type " + element + " not yet supported"); |
| } |
| |
| private static void bind(@NonNull Node node, @Nullable PsiElement element) { |
| if (element != null) { |
| node.setNativeNode(element); |
| } |
| node.setPositionFactory(POSITION_FACTORY); |
| } |
| |
| @NonNull |
| private static CompilationUnit toCompilationUnit(@NonNull PsiJavaFile psiJavaFile) { |
| CompilationUnit unit = new CompilationUnit(); |
| bind(unit, psiJavaFile); |
| |
| PsiPackageStatement packageStatement = psiJavaFile.getPackageStatement(); |
| if (packageStatement != null) { |
| PackageDeclaration packageDeclaration = new PackageDeclaration(); |
| bind(packageDeclaration, packageStatement); |
| PsiModifierList annotationList = packageStatement.getAnnotationList(); |
| if (annotationList != null) { |
| StrictListAccessor<Annotation, PackageDeclaration> annotations = packageDeclaration.astAnnotations(); |
| for (PsiAnnotation annotation : annotationList.getAnnotations()) { |
| annotations.addToEnd(toAnnotation(annotation)); |
| } |
| } |
| StrictListAccessor<Identifier, PackageDeclaration> identifiers = packageDeclaration.astParts(); |
| String pkg = packageStatement.getPackageReference().getQualifiedName(); |
| for (String part : DOT_SPLITTER.split(pkg)) { |
| Identifier identifier = Identifier.of(part); |
| bind(identifier, null); |
| identifiers.addToEnd(identifier); |
| } |
| |
| unit.astPackageDeclaration(packageDeclaration); |
| } |
| |
| |
| StrictListAccessor<ImportDeclaration, CompilationUnit> imports = unit.astImportDeclarations(); |
| PsiImportList importList = psiJavaFile.getImportList(); |
| if (importList != null) { |
| for (PsiImportStatementBase importStatement : importList.getAllImportStatements()) { |
| ImportDeclaration imp = new ImportDeclaration(); |
| StrictListAccessor<Identifier, ImportDeclaration> importParts = imp.astParts(); |
| PsiJavaCodeReferenceElement importReference = importStatement.getImportReference(); |
| if (importReference != null) { |
| for (String part : DOT_SPLITTER.split(importReference.getQualifiedName())) { |
| Identifier identifier = Identifier.of(part); |
| bind(identifier, null); |
| importParts.addToEnd(identifier); |
| } |
| } |
| |
| imp.astStarImport(importStatement.isOnDemand()); |
| if (importStatement instanceof PsiImportStaticStatement) { |
| imp.astStaticImport(true); |
| } |
| bind(imp, importStatement); |
| imports.addToEnd(imp); |
| } |
| } |
| |
| StrictListAccessor<TypeDeclaration, CompilationUnit> types = unit.astTypeDeclarations(); |
| for (PsiClass psiClass : psiJavaFile.getClasses()) { |
| TypeDeclaration type = toTypeDeclaration(psiClass); |
| types.addToEnd(type); |
| } |
| |
| return unit; |
| } |
| |
| @NonNull |
| private static TypeDeclaration toTypeDeclaration(@NonNull PsiClass psiClass) { |
| if (psiClass.isAnnotationType()) { |
| AnnotationDeclaration declaration = new AnnotationDeclaration(); |
| bind(declaration, psiClass); |
| PsiIdentifier nameIdentifier = psiClass.getNameIdentifier(); |
| if (nameIdentifier != null) { |
| declaration.astName(toIdentifier(nameIdentifier)); |
| } |
| PsiModifierList modifierList = psiClass.getModifierList(); |
| if (modifierList != null) { |
| declaration.astModifiers(toModifiers(modifierList)); |
| } |
| declaration.astBody(toTypeBody(psiClass)); |
| return declaration; |
| } else if (psiClass.isEnum()) { |
| EnumDeclaration declaration = new EnumDeclaration(); |
| bind(declaration, psiClass); |
| PsiIdentifier nameIdentifier = psiClass.getNameIdentifier(); |
| if (nameIdentifier != null) { |
| declaration.astName(toIdentifier(nameIdentifier)); |
| } |
| declaration = declaration.astBody(toEnumTypeBody(psiClass)); |
| PsiModifierList modifierList = psiClass.getModifierList(); |
| if (modifierList != null) { |
| declaration.astModifiers(toModifiers(modifierList)); |
| } |
| PsiReferenceList implementsList = psiClass.getImplementsList(); |
| if (implementsList != null) { |
| StrictListAccessor<TypeReference, EnumDeclaration> implementing = declaration.astImplementing(); |
| for (PsiJavaCodeReferenceElement ref : implementsList.getReferenceElements()) { |
| TypeReference typeReference = toTypeReference(ref); |
| implementing.addToEnd(typeReference); |
| } |
| } |
| return declaration; |
| } else if (psiClass.isInterface()) { |
| InterfaceDeclaration declaration = new InterfaceDeclaration(); |
| bind(declaration, psiClass); |
| PsiIdentifier nameIdentifier = psiClass.getNameIdentifier(); |
| if (nameIdentifier != null) { |
| declaration.astName(toIdentifier(nameIdentifier)); |
| } |
| PsiModifierList modifierList = psiClass.getModifierList(); |
| if (modifierList != null) { |
| declaration.astModifiers(toModifiers(modifierList)); |
| } |
| PsiReferenceList extendsList = psiClass.getExtendsList(); |
| if (extendsList != null) { |
| StrictListAccessor<TypeReference, InterfaceDeclaration> extending = declaration.astExtending(); |
| for (PsiJavaCodeReferenceElement ref : extendsList.getReferenceElements()) { |
| TypeReference typeReference = toTypeReference(ref); |
| extending.addToEnd(typeReference); |
| } |
| } |
| PsiTypeParameterList typeParameterList = psiClass.getTypeParameterList(); |
| if (typeParameterList != null) { |
| StrictListAccessor<TypeVariable, InterfaceDeclaration> typeVariables = declaration.astTypeVariables(); |
| for (PsiTypeParameter parameter : typeParameterList.getTypeParameters()) { |
| TypeVariable v = new TypeVariable(); |
| v.astName(toIdentifier(parameter.getName())); |
| bind(v, null); |
| typeVariables.addToEnd(v); |
| } |
| } |
| |
| declaration.astBody(toTypeBody(psiClass)); |
| return declaration; |
| } else { |
| ClassDeclaration declaration = new ClassDeclaration(); |
| bind(declaration, psiClass); |
| PsiModifierList modifierList = psiClass.getModifierList(); |
| if (modifierList != null) { |
| declaration.astModifiers(toModifiers(modifierList)); |
| } |
| PsiIdentifier nameIdentifier = psiClass.getNameIdentifier(); |
| if (nameIdentifier != null) { |
| declaration.astName(toIdentifier(nameIdentifier)); |
| } |
| PsiTypeParameterList typeParameterList = psiClass.getTypeParameterList(); |
| if (typeParameterList != null) { |
| StrictListAccessor<TypeVariable, ClassDeclaration> typeVariables = declaration.astTypeVariables(); |
| for (PsiTypeParameter parameter : typeParameterList.getTypeParameters()) { |
| TypeVariable v = new TypeVariable(); |
| v.astName(toIdentifier(parameter.getName())); |
| bind(v, null); |
| typeVariables.addToEnd(v); |
| } |
| } |
| |
| PsiReferenceList implementsList = psiClass.getImplementsList(); |
| if (implementsList != null) { |
| StrictListAccessor<TypeReference, ClassDeclaration> implementing = declaration.astImplementing(); |
| for (PsiJavaCodeReferenceElement ref : implementsList.getReferenceElements()) { |
| TypeReference typeReference = toTypeReference(ref); |
| implementing.addToEnd(typeReference); |
| } |
| } |
| |
| PsiReferenceList extendsList = psiClass.getExtendsList(); |
| if (extendsList != null) { |
| PsiJavaCodeReferenceElement[] referenceElements = extendsList.getReferenceElements(); |
| if (referenceElements.length > 0) { |
| TypeReference typeReference = toTypeReference(referenceElements[0]); |
| declaration.astExtending(typeReference); |
| } |
| } |
| |
| declaration.astBody(toTypeBody(psiClass)); |
| return declaration; |
| } |
| } |
| |
| @NonNull |
| private static NormalTypeBody toTypeBody(@NonNull PsiClass psiClass) { |
| NormalTypeBody body = new NormalTypeBody(); |
| bind(body, psiClass); |
| StrictListAccessor<TypeMember, NormalTypeBody> members = body.astMembers(); |
| |
| for (PsiClassInitializer initializer : psiClass.getInitializers()) { |
| PsiCodeBlock codeBlock = initializer.getBody(); |
| StaticInitializer s = new StaticInitializer(); |
| bind(s, codeBlock); |
| s.astBody(toBlock(codeBlock)); |
| members.addToEnd(s); |
| } |
| for (PsiField field : psiClass.getFields()) { |
| members.addToEnd(toField(field)); |
| } |
| for (PsiMethod method : psiClass.getMethods()) { |
| if (method.isConstructor()) { |
| members.addToEnd(toConstructorDeclaration(method)); |
| } else { |
| members.addToEnd(toMethodDeclaration(method)); |
| } |
| } |
| for (PsiClass innerClass : psiClass.getInnerClasses()) { |
| TypeDeclaration typeDeclaration = toTypeDeclaration(innerClass); |
| if (typeDeclaration instanceof TypeMember) { |
| members.addToEnd((TypeMember) typeDeclaration); |
| } |
| } |
| |
| PsiElement lBrace = psiClass.getLBrace(); |
| PsiElement rBrace = psiClass.getRBrace(); |
| if (lBrace != null && rBrace != null) { |
| int start = lBrace.getTextOffset(); |
| int end = rBrace.getTextOffset() + 1; |
| body.setPosition(new Position(start, end)); |
| } |
| return body; |
| } |
| |
| private static EnumConstant toEnumConstant(@NonNull PsiEnumConstant enumConstant) { |
| EnumConstant constant = new EnumConstant(); |
| bind(constant, enumConstant); |
| |
| constant.astName(toIdentifier(enumConstant.getNameIdentifier())); |
| PsiExpressionList argumentList = enumConstant.getArgumentList(); |
| if (argumentList != null) { |
| StrictListAccessor<Expression, EnumConstant> arguments = constant.astArguments(); |
| for (PsiExpression argument : argumentList.getExpressions()) { |
| arguments.addToEnd(toExpression(argument)); |
| } |
| } |
| StrictListAccessor<Annotation, EnumConstant> annotations = constant.astAnnotations(); |
| PsiModifierList modifierList = enumConstant.getModifierList(); |
| if (modifierList != null) { |
| for (PsiAnnotation annotation : modifierList.getAnnotations()) { |
| annotations.addToEnd(toAnnotation(annotation)); |
| } |
| } |
| PsiEnumConstantInitializer initializer = enumConstant.getInitializingClass(); |
| if (initializer != null) { |
| NormalTypeBody body = toTypeBody(initializer); |
| constant.astBody(body); |
| } |
| |
| return constant; |
| } |
| |
| @NonNull |
| private static EnumTypeBody toEnumTypeBody(@NonNull PsiClass psiClass) { |
| EnumTypeBody body = new EnumTypeBody(); |
| bind(body, null); |
| StrictListAccessor<TypeMember, EnumTypeBody> members = body.astMembers(); |
| |
| for (PsiClassInitializer initializer : psiClass.getInitializers()) { |
| PsiCodeBlock codeBlock = initializer.getBody(); |
| StaticInitializer s = new StaticInitializer(); |
| bind(s, codeBlock); |
| s.astBody(toBlock(codeBlock)); |
| members.addToEnd(s); |
| } |
| for (PsiField field : psiClass.getFields()) { |
| if (field instanceof PsiEnumConstant) { |
| PsiEnumConstant pec = (PsiEnumConstant)field; |
| EnumConstant enumConstant = toEnumConstant(pec); |
| body.astConstants().addToEnd(enumConstant); |
| } |
| } |
| for (PsiMethod method : psiClass.getMethods()) { |
| if (method.isConstructor()) { |
| members.addToEnd(toConstructorDeclaration(method)); |
| } else { |
| members.addToEnd(toMethodDeclaration(method)); |
| } |
| } |
| for (PsiClass innerClass : psiClass.getInnerClasses()) { |
| TypeDeclaration typeDeclaration = toTypeDeclaration(innerClass); |
| if (typeDeclaration instanceof TypeMember) { |
| members.addToEnd((TypeMember) typeDeclaration); |
| } |
| } |
| |
| return body; |
| } |
| |
| @Nullable |
| private static Modifiers toModifiers(@NonNull PsiModifierList list) { |
| Modifiers modifiers = new Modifiers(); |
| bind(modifiers, list); |
| |
| StrictListAccessor<Annotation, Modifiers> annotations = modifiers.astAnnotations(); |
| for (PsiAnnotation annotation : list.getAnnotations()) { |
| annotations.addToEnd(toAnnotation(annotation)); |
| } |
| |
| StrictListAccessor<KeywordModifier, Modifiers> keywords = modifiers.astKeywords(); |
| if (list.hasExplicitModifier(PsiModifier.PUBLIC)) { |
| KeywordModifier keyword = KeywordModifier.PUBLIC(); |
| bind(keyword, null); |
| keywords.addToEnd(keyword); |
| } else if (list.hasExplicitModifier(PsiModifier.PROTECTED)) { |
| KeywordModifier keyword = KeywordModifier.PROTECTED(); |
| bind(keyword, null); |
| keywords.addToEnd(keyword); |
| } else if (list.hasExplicitModifier(PsiModifier.PRIVATE)) { |
| KeywordModifier keyword = KeywordModifier.PRIVATE(); |
| bind(keyword, null); |
| keywords.addToEnd(keyword); |
| } |
| if (list.hasExplicitModifier(PsiModifier.STATIC)) { |
| KeywordModifier keyword = KeywordModifier.STATIC(); |
| bind(keyword, null); |
| keywords.addToEnd(keyword); |
| } |
| if (list.hasExplicitModifier(PsiModifier.ABSTRACT)) { |
| KeywordModifier keyword = new KeywordModifier().astName("abstract"); |
| bind(keyword, null); |
| keywords.addToEnd(keyword); |
| } |
| if (list.hasExplicitModifier(PsiModifier.FINAL)) { |
| KeywordModifier keyword = KeywordModifier.FINAL(); |
| bind(keyword, null); |
| keywords.addToEnd(keyword); |
| } |
| // TODO: Finish the rest. PsiFormatUtils#formatModifiers has some sample code |
| //KeywordModifier.fromReflectModifiers(0); |
| |
| return modifiers; |
| } |
| |
| @Nullable |
| private static AnnotationValue toAnnotationValue(@NonNull PsiAnnotationMemberValue value) { |
| if (value instanceof PsiLiteral) { |
| PsiLiteral literal = (PsiLiteral)value; |
| Object v = literal.getValue(); |
| if (v instanceof String) { |
| StringLiteral string = new StringLiteral(); |
| bind(string, value); |
| string.astValue((String)v); |
| return string; |
| } else if (v instanceof Integer) { |
| IntegralLiteral number = new IntegralLiteral(); |
| bind(number, value); |
| number.astIntValue((Integer)v); |
| return number; |
| } else if (v instanceof Long) { |
| IntegralLiteral number = new IntegralLiteral(); |
| number.astLongValue((Long)v); |
| bind(number, value); |
| return number; |
| } else if (v instanceof Float) { |
| FloatingPointLiteral number = new FloatingPointLiteral(); |
| bind(number, value); |
| number.astFloatValue((Float)v); |
| return number; |
| } else if (v instanceof Double) { |
| FloatingPointLiteral number = new FloatingPointLiteral(); |
| bind(number, value); |
| number.astDoubleValue((Double)v); |
| return number; |
| } else if (v instanceof Character) { |
| CharLiteral charLiteral = new CharLiteral(); |
| bind(charLiteral, value); |
| charLiteral.astValue((Character)v); |
| return charLiteral; |
| } |
| } else if (value instanceof PsiArrayInitializerMemberValue) { |
| PsiArrayInitializerMemberValue mv = (PsiArrayInitializerMemberValue)value; |
| ArrayInitializer initializer = new ArrayInitializer(); |
| bind(initializer, value); |
| StrictListAccessor<Expression, ArrayInitializer> expressions = initializer.astExpressions(); |
| for (PsiAnnotationMemberValue mmv : mv.getInitializers()) { |
| AnnotationValue annotationValue = toAnnotationValue(mmv); |
| if (annotationValue instanceof Expression) { |
| expressions.addToEnd((Expression) annotationValue); |
| } |
| } |
| return initializer; |
| } else if (value instanceof PsiExpression) { |
| return toExpression((PsiExpression) value); |
| } else if (value instanceof PsiAnnotation) { |
| return toAnnotation((PsiAnnotation) value); |
| } |
| |
| return null; |
| } |
| |
| @NonNull |
| private static Annotation toAnnotation(@NonNull PsiAnnotation annotation) { |
| Annotation a = new Annotation(); |
| bind(a, annotation); |
| TypeReference typeReference = null; |
| if (EXPAND_TYPES) { |
| typeReference = toTypeReference(annotation.getQualifiedName(), annotation); |
| } else { |
| PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement(); |
| if (referenceElement != null) { |
| typeReference = toTypeReference(referenceElement); |
| } |
| } |
| if (typeReference != null) { |
| a.astAnnotationTypeReference(typeReference); |
| } |
| StrictListAccessor<AnnotationElement, Annotation> elements = a.astElements(); |
| PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); |
| for (PsiNameValuePair pair : attributes) { |
| PsiAnnotationMemberValue value = pair.getValue(); |
| assert value != null : pair.getName(); |
| AnnotationValue v = toAnnotationValue(value); |
| if (v != null) { |
| AnnotationElement element = new AnnotationElement(); |
| bind(element, pair); |
| PsiIdentifier nameIdentifier = pair.getNameIdentifier(); |
| if (nameIdentifier != null) { |
| element.astName(toIdentifier(nameIdentifier)); |
| } |
| element.astValue(v); |
| elements.addToEnd(element); |
| } |
| } |
| return a; |
| } |
| |
| @NonNull |
| public static TypeReference toTypeReference(@NonNull PsiType type) { |
| String fqcn = type.getCanonicalText(); |
| if (fqcn.startsWith("java.lang.")) { //$NON-NLS-1$ |
| fqcn = fqcn.substring(10); |
| } |
| return toTypeReference(fqcn); |
| } |
| |
| @NonNull |
| private static TypeReference toTypeReference(@NonNull PsiJavaCodeReferenceElement reference) { |
| return toTypeReference(EXPAND_TYPES ? reference.getQualifiedName() : reference.getText(), reference); |
| } |
| |
| @NonNull |
| private static TypeReference toTypeReference(@NonNull PsiTypeElement type) { |
| return toTypeReference(EXPAND_TYPES ? type.getType().getCanonicalText() : type.getText(), type); |
| } |
| |
| @NonNull |
| private static TypeReference toTypeReference(@NonNull String fqcn, @Nullable PsiElement element) { |
| TypeReference reference = toTypeReference(fqcn); |
| bind(reference, element); |
| return reference; |
| } |
| |
| /** |
| * Parses the given type description string, which can include array and type parameters, and returns |
| * a corresponding Lombok AST {@link TypeReference} |
| * |
| * @param type the type string to parse |
| * @return a corresponding {@link TypeReference} |
| */ |
| @NonNull |
| private static TypeReference toTypeReference(@NonNull String type) { |
| // Type can be something like Map<Map<String[], List<Integer[]>>,List<String[]>>[] |
| // |
| TypeReference reference = new TypeReference(); |
| bind(reference, null); |
| |
| StrictListAccessor<TypeReferencePart, TypeReference> parts = reference.astParts(); |
| TypeReferencePart part = null; |
| int n = type.length(); |
| int index = 0; |
| int segmentStart = 0; |
| char c = 0; |
| while (index < n) { |
| c = type.charAt(index); |
| if (c == '<' || c == '[') { |
| break; |
| } else if (c == '.') { |
| // TODO: Handle varargs ... |
| part = new TypeReferencePart(); |
| bind(part, null); |
| part.astIdentifier(toIdentifier(type.substring(segmentStart, index))); |
| parts.addToEnd(part); |
| segmentStart = index + 1; |
| } |
| index++; |
| } |
| if (segmentStart < index) { |
| part = new TypeReferencePart(); |
| bind(part, null); |
| // In the common case, this is a type like "int" with nothing else; don't bother |
| // creating a substring of itself |
| String segment = (segmentStart == 0 && index == n) ? type : type.substring(segmentStart, index); |
| //if (n - index == 1 && type.charAt(index) == '?') { |
| // reference.astWildcard(WildcardKind.UNBOUND); |
| //} |
| part.astIdentifier(toIdentifier(segment)); |
| parts.addToEnd(part); |
| } |
| if (index != n && part != null) { |
| if (c == '<') { |
| int end = type.lastIndexOf('>'); |
| if (end != -1) { |
| StrictListAccessor<TypeReference, TypeReferencePart> typeArguments = part.astTypeArguments(); |
| int typeArgStart = index + 1; |
| int balance = 0; |
| for (int i = typeArgStart; i < end; i++) { |
| c = type.charAt(i); |
| if (c == '<') { |
| balance++; |
| } else if (c == '>') { |
| balance--; |
| } else if (c == ',' && balance == 0) { |
| // Trim whitespace |
| int typeArgEnd = i; |
| for (int j = i - 1; j >= typeArgStart; j--) { |
| if (Character.isWhitespace(type.charAt(j))) { |
| typeArgEnd--; |
| } else { |
| break; |
| } |
| } |
| typeArguments.addToEnd(toTypeReference(type.substring(typeArgStart, typeArgEnd))); |
| typeArgStart = i + 1; |
| while (typeArgStart < end) { |
| if (!Character.isWhitespace(type.charAt(typeArgStart))) { |
| break; |
| } |
| typeArgStart++; |
| } |
| } |
| } |
| if (typeArgStart < end) { |
| if (end == typeArgStart + 1 && type.charAt(typeArgStart) == '?') { |
| TypeReference r = new TypeReference(); |
| bind(r, null); |
| r.astWildcard(WildcardKind.UNBOUND); |
| typeArguments.addToEnd(r); |
| } else { |
| String substring = type.substring(typeArgStart, end); |
| typeArguments.addToEnd(toTypeReference(substring)); |
| } |
| } |
| } |
| index = end; |
| } |
| int arrayDimensions = 0; |
| for (int i = index; i < n; i++) { |
| if (type.charAt(i) == '[') { |
| arrayDimensions++; |
| } |
| } |
| if (arrayDimensions > 0) { |
| reference.astArrayDimensions(arrayDimensions); |
| } |
| } |
| |
| return reference; |
| } |
| |
| @Nullable |
| private static Expression toExpression(@NonNull PsiExpression expression) { |
| if (expression instanceof PsiLiteralExpression) { |
| // Literal does not implement Expression, but StringLiteral, BooleanLiteral, IntegralLiteral etc all do |
| return (Expression) toLiteral((PsiLiteralExpression)expression); |
| } else if (expression instanceof PsiBinaryExpression) { |
| PsiBinaryExpression p = (PsiBinaryExpression)expression; |
| BinaryExpression binary = new BinaryExpression(); |
| bind(binary, expression); |
| binary.astLeft(toExpression(p.getLOperand())); |
| PsiExpression rExpression = p.getROperand(); |
| if (rExpression != null) { |
| binary.astRight(toExpression(rExpression)); |
| } |
| |
| IElementType operation = p.getOperationTokenType(); |
| BinaryOperator operator = convertOperation(operation); |
| |
| if (operator != null) { |
| binary.astOperator(operator); |
| } else { |
| assert false : operation; |
| } |
| |
| return binary; |
| } else if (expression instanceof PsiAssignmentExpression) { |
| PsiAssignmentExpression p = (PsiAssignmentExpression)expression; |
| BinaryExpression binary = new BinaryExpression(); |
| bind(binary, expression); |
| BinaryOperator operator = BinaryOperator.ASSIGN; |
| IElementType operation = p.getOperationTokenType(); |
| if (operation == JavaTokenType.PLUSEQ) { |
| operator = BinaryOperator.PLUS_ASSIGN; |
| } |
| else if (operation == JavaTokenType.MINUSEQ) { |
| operator = BinaryOperator.MINUS_ASSIGN; |
| } |
| else if (operation == JavaTokenType.ASTERISKEQ) { |
| operator = BinaryOperator.MULTIPLY_ASSIGN; |
| } |
| else if (operation == JavaTokenType.DIVEQ) { |
| operator = BinaryOperator.DIVIDE_ASSIGN; |
| } |
| else if (operation == JavaTokenType.PERCEQ) { |
| operator = BinaryOperator.REMAINDER_ASSIGN; |
| } |
| else if (operation == JavaTokenType.ANDEQ) { |
| operator = BinaryOperator.AND_ASSIGN; |
| } |
| else if (operation == JavaTokenType.XOREQ) { |
| operator = BinaryOperator.XOR_ASSIGN; |
| } |
| else if (operation == JavaTokenType.OREQ) { |
| operator = BinaryOperator.OR_ASSIGN; |
| } |
| else if (operation == JavaTokenType.LTLTEQ) { |
| operator = BinaryOperator.SHIFT_LEFT_ASSIGN; |
| } |
| else if (operation == JavaTokenType.GTGTEQ) { |
| operator = BinaryOperator.SHIFT_RIGHT_ASSIGN; |
| } |
| else if (operation == JavaTokenType.GTGTGTEQ) { |
| operator = BinaryOperator.BITWISE_SHIFT_RIGHT_ASSIGN; |
| } |
| binary.astOperator(operator); |
| binary.astLeft(toExpression(p.getLExpression())); |
| PsiExpression rExpression = p.getRExpression(); |
| if (rExpression != null) { |
| Expression right = toExpression(rExpression); |
| if (right != null) { |
| binary.astRight(right); |
| } else { |
| assert false : rExpression; |
| } |
| } |
| return binary; |
| } else if (expression instanceof PsiQualifiedExpression) { |
| PsiQualifiedExpression p = (PsiQualifiedExpression)expression; |
| PsiJavaCodeReferenceElement qualifier = p.getQualifier(); |
| if (qualifier != null) { |
| Select operand = toSelect(qualifier); |
| Select select = new Select(); |
| bind(select, expression); |
| select.astOperand(operand); |
| PsiReference reference = p.getReference(); |
| if (reference != null) { |
| PsiElement referenceElement = reference.getElement(); |
| Identifier identifier = toIdentifier(referenceElement.getText()); |
| bind(identifier, referenceElement); |
| select.astIdentifier(identifier); |
| } |
| return select; |
| } |
| PsiReference reference = p.getReference(); |
| if (reference != null) { |
| return toVariableReference(reference); |
| } |
| if (p instanceof PsiSuperExpression) { |
| Super superExpression = new Super(); |
| bind(superExpression, p); |
| return superExpression; |
| } |
| return toVariableReference(p.getText(), p); |
| } else if (expression instanceof PsiReferenceExpression) { |
| PsiReferenceExpression refExpression = (PsiReferenceExpression)expression; |
| PsiElement qualifier = refExpression.getQualifier(); |
| if (qualifier == null) { |
| assert refExpression.getReferenceName() != null; |
| PsiReference reference = refExpression.getReference(); |
| if (reference != null) { |
| return toVariableReference(reference); |
| } |
| return null; |
| } |
| return toSelect(refExpression); |
| } else if (expression instanceof PsiCallExpression) { |
| return toMethodInvocation(expression); |
| } else if (expression instanceof PsiArrayAccessExpression) { |
| PsiArrayAccessExpression p = (PsiArrayAccessExpression)expression; |
| ArrayAccess arrayAccess = new ArrayAccess(); |
| bind(arrayAccess, p); |
| |
| PsiExpression indexExpression = p.getIndexExpression(); |
| if (indexExpression != null) { |
| arrayAccess.astIndexExpression(toExpression(indexExpression)); |
| } |
| arrayAccess.astOperand(toExpression(p.getArrayExpression())); |
| bind(arrayAccess, expression); |
| return arrayAccess; |
| } else if (expression instanceof PsiArrayInitializerExpression) { |
| return toArrayInitializer(expression); |
| } else if (expression instanceof PsiInstanceOfExpression) { |
| PsiInstanceOfExpression p = (PsiInstanceOfExpression)expression; |
| InstanceOf instanceOf = new InstanceOf(); |
| bind(instanceOf, expression); |
| PsiTypeElement checkType = p.getCheckType(); |
| if (checkType != null) { |
| instanceOf.astTypeReference(toTypeReference(checkType)); |
| } |
| instanceOf.astObjectReference(toExpression(p.getOperand())); |
| return instanceOf; |
| } else if (expression instanceof PsiConditionalExpression) { |
| PsiConditionalExpression p = (PsiConditionalExpression)expression; |
| InlineIfExpression inlineIf = new InlineIfExpression(); |
| bind(inlineIf, expression); |
| |
| inlineIf.astCondition(toExpression(p.getCondition())); |
| PsiExpression thenExpression = p.getThenExpression(); |
| if (thenExpression != null) { |
| inlineIf.astIfTrue(toExpression(thenExpression)); |
| } |
| PsiExpression elseExpression = p.getElseExpression(); |
| if (elseExpression != null) { |
| inlineIf.astIfFalse(toExpression(elseExpression)); |
| } |
| return inlineIf; |
| } else if (expression instanceof PsiClassObjectAccessExpression) { |
| PsiClassObjectAccessExpression p = (PsiClassObjectAccessExpression)expression; |
| ClassLiteral literal = new ClassLiteral(); |
| bind(literal, p); |
| literal.astTypeReference(toTypeReference(p.getOperand())); |
| return literal; |
| } else if (expression instanceof PsiParenthesizedExpression) { |
| PsiParenthesizedExpression p = (PsiParenthesizedExpression)expression; |
| PsiExpression e = p.getExpression(); |
| if (e != null) { |
| return toExpression(e); |
| } |
| return null; |
| } else if (expression instanceof PsiTypeCastExpression) { |
| PsiTypeCastExpression p = (PsiTypeCastExpression)expression; |
| Cast cast = new Cast(); |
| bind(cast, expression); |
| PsiTypeElement castType = p.getCastType(); |
| if (castType != null) { |
| cast.astTypeReference(toTypeReference(castType)); |
| } |
| PsiExpression operand = p.getOperand(); |
| if (operand != null) { |
| cast.astOperand(toExpression(operand)); |
| } |
| return cast; |
| } else if (expression instanceof PsiPostfixExpression) { |
| PsiPostfixExpression p = (PsiPostfixExpression)expression; |
| UnaryExpression unary = new UnaryExpression(); |
| bind(unary, expression); |
| IElementType operation = p.getOperationTokenType(); |
| UnaryOperator operator = null; |
| if (operation == JavaTokenType.MINUSMINUS) { |
| operator = UnaryOperator.POSTFIX_DECREMENT; |
| } else if (operation == JavaTokenType.PLUSPLUS) { |
| operator = UnaryOperator.POSTFIX_INCREMENT; |
| } |
| if (operator != null) { |
| unary.astOperator(operator); |
| } else { |
| assert false : operation; |
| } |
| unary.astOperand(toExpression(p.getOperand())); |
| return unary; |
| } else if (expression instanceof PsiPrefixExpression) { |
| PsiPrefixExpression p = (PsiPrefixExpression)expression; |
| UnaryExpression unary = new UnaryExpression(); |
| bind(unary, expression); |
| |
| IElementType operation = p.getOperationTokenType(); |
| UnaryOperator operator = null; |
| if (operation == JavaTokenType.MINUSMINUS) { |
| operator = UnaryOperator.PREFIX_DECREMENT; |
| } else if (operation == JavaTokenType.PLUSPLUS) { |
| operator = UnaryOperator.PREFIX_INCREMENT; |
| } else if (operation == JavaTokenType.MINUS) { |
| operator = UnaryOperator.UNARY_MINUS; |
| } else if (operation == JavaTokenType.PLUS) { |
| operator = UnaryOperator.UNARY_PLUS; |
| } else if (operation == JavaTokenType.EXCL) { |
| operator = UnaryOperator.LOGICAL_NOT; |
| } else if (operation == JavaTokenType.TILDE) { |
| operator = UnaryOperator.BINARY_NOT; |
| } |
| if (operator != null) { |
| unary.astOperator(operator); |
| } else { |
| assert false : operation; |
| } |
| PsiExpression operand = p.getOperand(); |
| if (operand != null) { |
| unary.astOperand(toExpression(operand)); |
| } |
| return unary; |
| } else if (expression instanceof PsiPolyadicExpression) { |
| // Example: A + B + C + D; IDEA parses this as a single |
| // polyadic expression with operator type + of A, B, C and D. |
| // Fold them into nested BinaryExpressions for Lombok. |
| PsiPolyadicExpression p = (PsiPolyadicExpression)expression; |
| IElementType operation = p.getOperationTokenType(); |
| BinaryOperator operator = convertOperation(operation); |
| if (operator == null) { |
| assert false : operation; |
| } |
| PsiExpression[] operands = p.getOperands(); |
| assert operands.length >= 1; |
| Expression left = toExpression(operands[0]); |
| for (int i = 1, n = operands.length; i < n; i++) { |
| Expression right = toExpression(operands[i]); |
| BinaryExpression binary = new BinaryExpression(); |
| bind(binary, expression); |
| binary.astOperator(operator); |
| |
| binary.astLeft(left); |
| binary.astRight(right); |
| |
| left = binary; |
| } |
| |
| return left; |
| } else if (expression instanceof PsiLambdaExpression) { |
| // Is this used in Java? |
| // TODO: Implement. Not yet used by lint. |
| return null; |
| } |
| return null; |
| } |
| |
| @Nullable |
| private static BinaryOperator convertOperation(IElementType operation) { |
| BinaryOperator operator = null; |
| if (operation == JavaTokenType.EQEQ) { |
| operator = BinaryOperator.EQUALS; |
| } |
| else if (operation == JavaTokenType.EQ) { |
| operator = BinaryOperator.ASSIGN; |
| } |
| else if (operation == JavaTokenType.OROR) { |
| operator = BinaryOperator.LOGICAL_OR; |
| } |
| else if (operation == JavaTokenType.ANDAND) { |
| operator = BinaryOperator.LOGICAL_AND; |
| } |
| else if (operation == JavaTokenType.NE) { |
| operator = BinaryOperator.NOT_EQUALS; |
| } |
| else if (operation == JavaTokenType.GT) { |
| operator = BinaryOperator.GREATER; |
| } |
| else if (operation == JavaTokenType.GE) { |
| operator = BinaryOperator.GREATER_OR_EQUAL; |
| } |
| else if (operation == JavaTokenType.LT) { |
| operator = BinaryOperator.LESS; |
| } |
| else if (operation == JavaTokenType.LE) { |
| operator = BinaryOperator.LESS_OR_EQUAL; |
| } |
| else if (operation == JavaTokenType.OR) { |
| operator = BinaryOperator.BITWISE_OR; |
| } |
| else if (operation == JavaTokenType.AND) { |
| operator = BinaryOperator.BITWISE_AND; |
| } |
| else if (operation == JavaTokenType.XOR) { |
| operator = BinaryOperator.BITWISE_XOR; |
| } |
| else if (operation == JavaTokenType.LTLT) { |
| operator = BinaryOperator.SHIFT_LEFT; |
| } |
| else if (operation == JavaTokenType.GTGT) { |
| operator = BinaryOperator.SHIFT_RIGHT; |
| } |
| else if (operation == JavaTokenType.GTGTGT) { |
| operator = BinaryOperator.BITWISE_SHIFT_RIGHT; |
| } |
| else if (operation == JavaTokenType.PLUS) { |
| operator = BinaryOperator.PLUS; |
| } |
| else if (operation == JavaTokenType.MINUS) { |
| operator = BinaryOperator.MINUS; |
| } |
| else if (operation == JavaTokenType.ASTERISK) { |
| operator = BinaryOperator.MULTIPLY; |
| } |
| else if (operation == JavaTokenType.DIV) { |
| operator = BinaryOperator.DIVIDE; |
| } |
| else if (operation == JavaTokenType.PERC) { |
| operator = BinaryOperator.REMAINDER; |
| } |
| return operator; |
| } |
| |
| @NonNull |
| private static ArrayInitializer toArrayInitializer(@NonNull PsiExpression expression) { |
| PsiArrayInitializerExpression p = (PsiArrayInitializerExpression)expression; |
| ArrayInitializer arrayInitializer = new ArrayInitializer(); |
| bind(arrayInitializer, expression); |
| StrictListAccessor<Expression, ArrayInitializer> expressions = arrayInitializer.astExpressions(); |
| for (PsiExpression psiExpression : p.getInitializers()) { |
| expressions.addToEnd(toExpression(psiExpression)); |
| } |
| bind(arrayInitializer, expression); |
| return arrayInitializer; |
| } |
| |
| @Nullable |
| private static Expression toMethodInvocation(@NonNull PsiExpression expression) { |
| if (expression instanceof PsiNewExpression) { |
| PsiNewExpression p = (PsiNewExpression)expression; |
| |
| // Array? |
| PsiExpression[] arrayDimensions = p.getArrayDimensions(); |
| PsiArrayInitializerExpression arrayInitializer = p.getArrayInitializer(); |
| if (arrayDimensions.length > 0 || arrayInitializer != null) { |
| ArrayCreation creation = new ArrayCreation(); |
| bind(creation, arrayInitializer); |
| PsiType type = p.getType(); |
| if (type != null) { |
| TypeReference typeReference = toTypeReference(type); |
| bind(typeReference, p); |
| |
| // Workaround to avoid getting double array dimensions from this |
| // and the ArrayCreation code below |
| if (arrayDimensions.length != 0) { |
| typeReference.astArrayDimensions(0); |
| } |
| |
| creation.astComponentTypeReference(typeReference); |
| } |
| if (arrayInitializer != null) { |
| creation.astInitializer(toArrayInitializer(arrayInitializer)); |
| } |
| StrictListAccessor<ArrayDimension, ArrayCreation> dimensions = creation.astDimensions(); |
| for (PsiExpression dimension : arrayDimensions) { |
| ArrayDimension d = new ArrayDimension(); |
| bind(d, dimension); |
| d.astDimension(toExpression(dimension)); |
| dimensions.addToEnd(d); |
| } |
| |
| return creation; |
| } |
| |
| ConstructorInvocation invocation = new ConstructorInvocation(); |
| bind(invocation, p); |
| PsiJavaCodeReferenceElement classOrAnonymousClassReference = p.getClassOrAnonymousClassReference(); |
| if (classOrAnonymousClassReference != null) { |
| invocation.astTypeReference(toTypeReference(classOrAnonymousClassReference)); |
| } |
| StrictListAccessor<Expression, ConstructorInvocation> arguments = invocation.astArguments(); |
| PsiExpressionList argumentList = p.getArgumentList(); |
| if (argumentList != null) { |
| for (PsiExpression argument : argumentList.getExpressions()) { |
| arguments.addToEnd(toExpression(argument)); |
| } |
| } |
| PsiAnonymousClass anonymousClass = p.getAnonymousClass(); |
| if (anonymousClass != null) { |
| NormalTypeBody body = toTypeBody(anonymousClass); |
| invocation.astAnonymousClassBody(body); |
| } |
| |
| bind(invocation, expression); |
| return invocation; |
| } else if (expression instanceof PsiMethodCallExpression) { |
| PsiMethodCallExpression p = (PsiMethodCallExpression)expression; |
| MethodInvocation invocation = new MethodInvocation(); |
| bind(invocation, expression); |
| |
| StrictListAccessor<TypeReference, MethodInvocation> types = invocation.astMethodTypeArguments(); |
| for (PsiTypeElement t : p.getTypeArgumentList().getTypeParameterElements()) { |
| TypeReference typeReference = toTypeReference(t); |
| types.addToEnd(typeReference); |
| } |
| |
| StrictListAccessor <Expression, MethodInvocation> arguments = invocation.astArguments(); |
| PsiExpressionList argumentList = p.getArgumentList(); |
| for (PsiExpression argument : argumentList.getExpressions()) { |
| arguments.addToEnd(toExpression(argument)); |
| } |
| PsiReferenceExpression methodExpression = p.getMethodExpression(); |
| PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); |
| if (qualifierExpression != null) { |
| invocation.astOperand(toExpression(qualifierExpression)); |
| } |
| String referenceName = methodExpression.getReferenceName(); |
| if (referenceName != null) { |
| Identifier name = toIdentifier(referenceName); |
| PsiElement referenceNameElement = methodExpression.getReferenceNameElement(); |
| if (referenceNameElement != null) { |
| bind(name, referenceNameElement); |
| } |
| invocation.astName(name); |
| } |
| |
| return invocation; |
| } else { |
| // TODO: When is something a PsiCallExpression but not constructor or method? Perhaps for other languages? |
| return null; |
| } |
| } |
| |
| @Nullable |
| private static Statement toStatement(@NonNull PsiStatement statement) { |
| if (statement instanceof PsiExpressionStatement) { |
| PsiExpressionStatement p = (PsiExpressionStatement)statement; |
| ExpressionStatement s = new ExpressionStatement(); |
| bind(s, statement); |
| s.astExpression(toExpression(p.getExpression())); |
| return s; |
| } else if (statement instanceof PsiDeclarationStatement) { |
| PsiDeclarationStatement pds = (PsiDeclarationStatement)statement; |
| return toVariableDeclaration(pds); |
| } else if (statement instanceof PsiBlockStatement) { |
| PsiBlockStatement p = (PsiBlockStatement)statement; |
| return toBlock(p.getCodeBlock()); |
| } else if (statement instanceof PsiIfStatement) { |
| PsiIfStatement p = (PsiIfStatement)statement; |
| If ifStatement = new If(); |
| bind(ifStatement, statement); |
| PsiExpression condition = p.getCondition(); |
| if (condition != null) { |
| Expression ifCondition = toExpression(condition); |
| assert ifCondition != null; |
| ifStatement.astCondition(ifCondition); |
| } |
| PsiStatement thenBranch = p.getThenBranch(); |
| if (thenBranch != null) { |
| ifStatement.astStatement(toStatement(thenBranch)); |
| } |
| PsiStatement elseBranch = p.getElseBranch(); |
| if (elseBranch != null) { |
| ifStatement.astElseStatement(toStatement(elseBranch)); |
| } |
| return ifStatement; |
| } else if (statement instanceof PsiReturnStatement) { |
| PsiReturnStatement p = (PsiReturnStatement)statement; |
| Return r = new Return(); |
| bind(r, statement); |
| PsiExpression returnValue = p.getReturnValue(); |
| if (returnValue != null) { |
| r.astValue(toExpression(returnValue)); |
| } |
| return r; |
| } else if (statement instanceof PsiLoopStatement) { |
| if (statement instanceof PsiForStatement) { |
| PsiForStatement p = (PsiForStatement)statement; |
| For f = new For(); |
| bind(f, statement); |
| PsiExpression condition = p.getCondition(); |
| if (condition != null) { |
| f.astCondition(toExpression(condition)); |
| } |
| PsiStatement update = p.getUpdate(); |
| if (update != null) { |
| StrictListAccessor<Expression, For> updates = f.astUpdates(); |
| if (update instanceof PsiExpressionListStatement) { |
| PsiExpressionListStatement pl = (PsiExpressionListStatement)update; |
| for (PsiExpression e : pl.getExpressionList().getExpressions()) { |
| updates.addToEnd(toExpression(e)); |
| } |
| } else { |
| assert update instanceof PsiExpressionStatement : update; |
| PsiExpressionStatement ps = (PsiExpressionStatement)update; |
| updates.addToEnd(toExpression(ps.getExpression())); |
| } |
| } |
| PsiStatement initialization = p.getInitialization(); |
| if (initialization != null) { |
| if (initialization instanceof PsiDeclarationStatement) { |
| PsiDeclarationStatement pds = (PsiDeclarationStatement)initialization; |
| f.astVariableDeclaration(toVariableDefinition(pds, pds.getDeclaredElements())); |
| } else if (initialization instanceof PsiExpressionStatement) { |
| PsiExpressionStatement expressionStatement = (PsiExpressionStatement)initialization; |
| f.astExpressionInits().addToEnd(toExpression(expressionStatement.getExpression())); |
| } else if (initialization instanceof PsiExpression) { |
| PsiExpression expression = (PsiExpression)initialization; |
| f.astExpressionInits().addToEnd(toExpression(expression)); |
| } else if (initialization instanceof PsiExpressionListStatement) { |
| PsiExpressionList expressionList = ((PsiExpressionListStatement)initialization).getExpressionList(); |
| if (expressionList != null) { |
| for (PsiExpression expression : expressionList.getExpressions()) { |
| f.astExpressionInits().addToEnd(toExpression(expression)); |
| } |
| } |
| } else if (initialization instanceof PsiEmptyStatement) { |
| // Do nothing; we don't need an explicit lombok.ast.EmptyStatement here |
| } else { |
| // Unexpected type of initializer |
| assert false : initialization + " for code " + initialization.getText(); |
| } |
| } |
| PsiStatement body = p.getBody(); |
| if (body != null) { |
| f.astStatement(toStatement(body)); |
| } |
| return f; |
| } else if (statement instanceof PsiForeachStatement) { |
| PsiForeachStatement p = (PsiForeachStatement)statement; |
| ForEach f = new ForEach(); |
| bind(f, statement); |
| PsiExpression iteratedValue = p.getIteratedValue(); |
| if (iteratedValue != null) { |
| f.astIterable(toExpression(iteratedValue)); |
| } |
| f.astVariable(toVariableDefinition(p.getIterationParameter())); |
| PsiStatement body = p.getBody(); |
| if (body != null) { |
| f.astStatement(toStatement(body)); |
| } |
| return f; |
| } else if (statement instanceof PsiDoWhileStatement) { |
| PsiDoWhileStatement p = (PsiDoWhileStatement)statement; |
| DoWhile w = new DoWhile(); |
| bind(w, statement); |
| PsiExpression condition = p.getCondition(); |
| if (condition != null) { |
| w.astCondition(toExpression(condition)); |
| } |
| PsiStatement body = p.getBody(); |
| if (body != null) { |
| w.astStatement(toStatement(body)); |
| } |
| return w; |
| } else if (statement instanceof PsiWhileStatement) { |
| PsiWhileStatement p = (PsiWhileStatement)statement; |
| While w = new While(); |
| bind(w, statement); |
| PsiExpression condition = p.getCondition(); |
| if (condition != null) { |
| w.astCondition(toExpression(condition)); |
| } |
| PsiStatement body = p.getBody(); |
| if (body != null) { |
| w.astStatement(toStatement(body)); |
| } |
| return w; |
| } else { |
| assert false : statement; // Shouldn't happen; PSI currently only has the above 4 |
| return null; |
| } |
| } else if (statement instanceof PsiSwitchStatement) { |
| PsiSwitchStatement p = (PsiSwitchStatement)statement; |
| Switch s = new Switch(); |
| bind(s, statement); |
| PsiExpression expression = p.getExpression(); |
| if (expression != null) { |
| s.astCondition(toExpression(expression)); |
| } |
| PsiCodeBlock body = p.getBody(); |
| if (body != null) { |
| s.astBody(toBlock(body)); |
| } |
| return s; |
| } else if (statement instanceof PsiBreakStatement) { |
| PsiBreakStatement p = (PsiBreakStatement)statement; |
| Break s = new Break(); |
| bind(s, p); |
| PsiIdentifier labelIdentifier = p.getLabelIdentifier(); |
| if (labelIdentifier != null) { |
| s.astLabel(toIdentifier(labelIdentifier)); |
| } |
| return s; |
| } else if (statement instanceof PsiSwitchLabelStatement) { |
| PsiSwitchLabelStatement p = (PsiSwitchLabelStatement)statement; |
| Case c = new Case(); |
| bind(c, statement); |
| PsiExpression caseValue = p.getCaseValue(); |
| if (caseValue != null) { |
| c.astCondition(toExpression(caseValue)); |
| } |
| return c; |
| } else if (statement instanceof PsiLabeledStatement) { |
| PsiLabeledStatement p = (PsiLabeledStatement)statement; |
| LabelledStatement l = new LabelledStatement(); |
| bind(l, statement); |
| l.astLabel(toIdentifier(p.getLabelIdentifier())); |
| PsiStatement s = p.getStatement(); |
| if (s != null) { |
| l.astStatement(toStatement(s)); |
| } |
| return l; |
| } else if (statement instanceof PsiSynchronizedStatement) { |
| PsiSynchronizedStatement p = (PsiSynchronizedStatement)statement; |
| Synchronized s = new Synchronized(); |
| bind(s, statement); |
| PsiExpression lockExpression = p.getLockExpression(); |
| if (lockExpression != null) { |
| s.astLock(toExpression(lockExpression)); |
| } |
| PsiCodeBlock body = p.getBody(); |
| if (body != null) { |
| s.astBody(toBlock(body)); |
| } |
| return s; |
| } else if (statement instanceof PsiContinueStatement) { |
| PsiContinueStatement p = (PsiContinueStatement)statement; |
| Continue c = new Continue(); |
| bind(c, statement); |
| PsiIdentifier labelIdentifier = p.getLabelIdentifier(); |
| if (labelIdentifier != null) { |
| c.astLabel(toIdentifier(labelIdentifier)); |
| } |
| return c; |
| } else { |
| if (statement instanceof PsiTryStatement) { |
| PsiTryStatement p = (PsiTryStatement)statement; |
| Try t = new Try(); |
| bind(t, statement); |
| |
| StrictListAccessor<Catch, Try> catches = t.astCatches(); |
| for (PsiCatchSection catchSection : p.getCatchSections()) { |
| Catch c = new Catch(); |
| bind(c, catchSection); |
| PsiParameter parameter = catchSection.getParameter(); |
| if (parameter != null) { |
| c.astExceptionDeclaration(toVariableDefinition(parameter)); |
| } |
| PsiCodeBlock catchBlock = catchSection.getCatchBlock(); |
| if (catchBlock != null) { |
| c.astBody(toBlock(catchBlock)); |
| } |
| catches.addToEnd(c); |
| } |
| |
| PsiCodeBlock tryBlock = p.getTryBlock(); |
| if (tryBlock != null) { |
| t.astBody(toBlock(tryBlock)); |
| } |
| |
| PsiCodeBlock finallyBlock = p.getFinallyBlock(); |
| if (finallyBlock != null) { |
| t.astFinally(toBlock(finallyBlock)); |
| } |
| |
| return t; |
| } |
| else if (statement instanceof PsiEmptyStatement) { |
| EmptyStatement emptyStatement = new EmptyStatement(); |
| bind(emptyStatement, statement); |
| return emptyStatement; |
| } |
| else if (statement instanceof PsiAssertStatement) { |
| PsiAssertStatement p = (PsiAssertStatement)statement; |
| Assert a = new Assert(); |
| bind(a, statement); |
| PsiExpression assertCondition = p.getAssertCondition(); |
| if (assertCondition != null) { |
| a.astAssertion(toExpression(assertCondition)); |
| } |
| PsiExpression assertDescription = p.getAssertDescription(); |
| if (assertDescription != null) { |
| a.astMessage(toExpression(assertDescription)); |
| } |
| return a; |
| } |
| else if (statement instanceof PsiThrowStatement) { |
| PsiThrowStatement p = (PsiThrowStatement)statement; |
| Throw t = new Throw(); |
| bind(t, statement); |
| PsiExpression exception = p.getException(); |
| if (exception != null) { |
| t.astThrowable(toExpression(exception)); |
| } |
| return t; |
| } |
| else if (statement instanceof PsiExpressionListStatement) { |
| // This shouldn't happen; we should never call this method, since |
| // PsiExpressionListStatement is only allowed as part of a for statement, |
| // and we deliberately handle this above as part of the for label conversion |
| // (since Lombok does not have a separate AST class for this) |
| assert false; |
| return null; |
| } else if (statement instanceof PsiClassLevelDeclarationStatement) { |
| //PsiClassLevelDeclarationStatement p = (PsiClassLevelDeclarationStatement)statement; |
| // Not clear what this is used for... |
| return null; |
| } |
| else { |
| // Surprise!! What's this? |
| // TODO: Implement. Not yet used by lint. |
| throw new UnsupportedOperationException("Unknown statement type for " + statement); |
| } |
| } |
| } |
| |
| @NonNull |
| private static Block toBlock(@NonNull PsiCodeBlock block) { |
| Block b = new Block(); |
| bind(b, block); |
| |
| StrictListAccessor<Statement, Block> statements = b.astContents(); |
| for (PsiStatement statement : block.getStatements()) { |
| Statement s = toStatement(statement); |
| // In theory all statements should be non null, but since I haven't mapped |
| // ALL constructs to Lombok yet (since Lint doesn't need it), I'm returning null |
| // here for stuff we don't care about yet |
| if (s != null) { |
| statements.addToEnd(s); |
| } |
| } |
| |
| return b; |
| } |
| |
| @NonNull |
| private static Identifier toIdentifier(@NonNull String identifierText) { |
| assert identifierText.indexOf('.') == -1 : identifierText; |
| Identifier identifier = Identifier.of(identifierText); |
| bind(identifier, null); |
| return identifier; |
| } |
| |
| @NonNull |
| private static Identifier toIdentifier(@NonNull PsiIdentifier element) { |
| Identifier identifier = Identifier.of(element.getText()); |
| bind(identifier, element); |
| return identifier; |
| } |
| |
| @Nullable |
| private static Literal toLiteral(@NonNull PsiLiteralExpression expression) { |
| Literal literal = null; |
| PsiType type = expression.getType(); |
| if (type == PsiType.NULL) { |
| literal = new NullLiteral(); |
| bind(literal, expression); |
| } else if (type == PsiType.INT || type == PsiType.LONG || type == PsiType.SHORT |
| || type == PsiType.BYTE) { |
| literal = new IntegralLiteral().rawValue(expression.getText()); |
| bind(literal, expression); |
| } else if (type == PsiType.BOOLEAN) { |
| literal = new BooleanLiteral().rawValue(expression.getText()); |
| bind(literal, expression); |
| } else if (type == PsiType.DOUBLE || type == PsiType.FLOAT) { |
| literal = new FloatingPointLiteral().rawValue(expression.getText()); |
| bind(literal, expression); |
| } else if (type == PsiType.CHAR) { |
| literal = new CharLiteral().rawValue(expression.getText()); |
| bind(literal, expression); |
| } else if (type != null && type.getCanonicalText().equals(CommonClassNames.JAVA_LANG_STRING)) { |
| StringLiteral stringLiteral = new StringLiteral(); |
| literal = stringLiteral.rawValue(expression.getText()); |
| bind(literal, expression); |
| if (stringLiteral.astValue() == null) { |
| Object value = expression.getValue(); |
| String string = value instanceof String ? (String)value : expression.getText(); |
| stringLiteral.astValue(string); |
| } |
| } |
| |
| return literal; |
| } |
| |
| @NonNull |
| private static VariableReference toVariableReference(@NonNull PsiIdentifier identifier) { |
| VariableReference variableReference = new VariableReference(); |
| bind(variableReference, identifier); |
| variableReference.astIdentifier(toIdentifier(identifier)); |
| return variableReference; |
| } |
| |
| @NonNull |
| private static VariableReference toVariableReference(@NonNull PsiReference reference) { |
| PsiElement element = reference.getElement(); |
| VariableReference variableReference = new VariableReference(); |
| bind(variableReference, element); |
| @SuppressWarnings("ConstantConditions") |
| Identifier identifier = toIdentifier(EXPAND_TYPES ? reference.getCanonicalText() : reference.getElement().getText()); |
| bind(identifier, element); |
| variableReference.astIdentifier(identifier); |
| return variableReference; |
| } |
| |
| @NonNull |
| private static VariableReference toVariableReference(@NonNull String identifier, @Nullable PsiElement element) { |
| VariableReference variableReference = new VariableReference(); |
| bind(variableReference, element); |
| Identifier name = toIdentifier(identifier); |
| variableReference.astIdentifier(name); |
| return variableReference; |
| } |
| |
| @NonNull |
| private static VariableDefinitionEntry toVariableDefinitionEntry(@NonNull PsiVariable variable) { |
| VariableDefinitionEntry entry = new VariableDefinitionEntry(); |
| bind(entry, variable); |
| PsiIdentifier nameIdentifier = variable.getNameIdentifier(); |
| if (nameIdentifier != null) { |
| entry.astName(toIdentifier(nameIdentifier)); |
| } |
| PsiExpression initializer = variable.getInitializer(); |
| if (initializer != null) { |
| entry.astInitializer(toExpression(initializer)); |
| } |
| return entry; |
| } |
| |
| @NonNull |
| static VariableDefinition toVariableDefinition(@NonNull PsiVariable variable) { |
| VariableDefinition definition = new VariableDefinition(); |
| bind(definition, variable); |
| PsiModifierList modifierList = variable.getModifierList(); |
| if (modifierList != null) { |
| definition.astModifiers(toModifiers(modifierList)); |
| } |
| |
| PsiTypeElement type = variable.getTypeElement(); |
| if (type != null) { |
| definition.astTypeReference(toTypeReference(type)); |
| // TODO: Handle |
| //if (variable.getType().getCanonicalText().endsWith(VARARG_SUFFIX)) { |
| // definition.astVarargs(true); |
| //} |
| } |
| |
| int arrayDimensions = variable.getType().getArrayDimensions(); |
| if (arrayDimensions != 0) { |
| TypeReference typeReference = definition.astTypeReference(); |
| if (typeReference != null) { |
| typeReference.astArrayDimensions(arrayDimensions); |
| } |
| } |
| |
| VariableDefinitionEntry entry = toVariableDefinitionEntry(variable); |
| definition.astVariables().addToEnd(entry); |
| |
| return definition; |
| } |
| |
| private static void setOperand(@NonNull Select select, @NonNull PsiElement qualifier) { |
| if (qualifier instanceof PsiIdentifier) { |
| // A little weird but this is how Lombok models it: |
| select.astOperand(toVariableReference((PsiIdentifier)qualifier)); |
| } else if (qualifier instanceof PsiSuperExpression) { |
| Super operand = new Super(); |
| bind(operand, qualifier); |
| select.astOperand(operand); |
| } else if (qualifier instanceof PsiThisExpression) { |
| This operand = new This(); |
| bind(operand, qualifier); |
| select.astOperand(operand); |
| } else if (qualifier instanceof PsiReferenceExpression) { |
| select.astOperand(toSelect((PsiReferenceExpression) qualifier)); |
| } else if (qualifier instanceof PsiCallExpression) { |
| select.astOperand(toMethodInvocation((PsiCallExpression)qualifier)); |
| } else if (qualifier instanceof PsiExpression) { |
| select.astOperand(toExpression((PsiExpression)qualifier)); |
| } else { |
| throw new UnsupportedOperationException("Unknown select qualifier type: " + qualifier); |
| } |
| } |
| |
| @NonNull |
| private static Select toSelect(@NonNull PsiQualifiedReferenceElement reference) { |
| Select select = new Select(); |
| bind(select, reference); |
| |
| Identifier nameIdentifier = Identifier.of(reference.getReferenceName()); |
| bind(nameIdentifier, null); |
| select.astIdentifier(nameIdentifier); |
| |
| PsiElement qualifier = reference.getQualifier(); |
| if (qualifier != null) { |
| setOperand(select, qualifier); |
| } |
| |
| return select; |
| } |
| |
| @Nullable |
| private static Expression toSelect(@NonNull PsiReferenceExpression reference) { |
| PsiExpression qualifier = reference.getQualifierExpression(); |
| String referenceName = reference.getReferenceName(); |
| if (qualifier != null && referenceName != null) { |
| Select select = new Select(); |
| bind(select, reference); |
| |
| Identifier nameIdentifier = Identifier.of(referenceName); |
| bind(nameIdentifier, null); |
| select.astIdentifier(nameIdentifier); |
| |
| setOperand(select, qualifier); |
| return select; |
| } else if (qualifier != null) { |
| return toExpression(qualifier); |
| } else if (referenceName != null) { |
| return toVariableReference(referenceName, qualifier); |
| } |
| |
| return null; |
| } |
| |
| @NonNull |
| private static Expression toSelect(@NonNull String fqcn, @Nullable PsiElement element) { |
| Select select = null; |
| |
| Iterator<String> iterator = DOT_SPLITTER.split(fqcn).iterator(); |
| String first = iterator.next(); |
| Expression operand = toVariableReference(first, null); |
| while (iterator.hasNext()) { |
| String name = iterator.next(); |
| select = new Select(); |
| bind(select, null); |
| Identifier identifier = Identifier.of(name); |
| bind(identifier, null); |
| select.astIdentifier(identifier); |
| select.astOperand(operand); |
| select.astIdentifier(identifier); |
| operand = select; |
| } |
| |
| if (select != null) { |
| bind(select, element); |
| assert select.toString().equals(fqcn) : fqcn; |
| } else { |
| return operand; |
| } |
| |
| return select; |
| } |
| |
| @NonNull |
| private static VariableDeclaration toField(@NonNull PsiVariable field) { |
| // Lombok does not distinguish between fields and variables |
| return toVariableDeclaration(field); |
| } |
| |
| @NonNull |
| private static Statement toVariableDeclaration(@NonNull PsiDeclarationStatement statement) { |
| PsiElement[] declaredElements = statement.getDeclaredElements(); |
| if (declaredElements.length == 1 && declaredElements[0].getNode().getElementType() == JavaElementType.CLASS) { |
| // Class declaration inside method |
| TypeDeclaration typeDeclaration = toTypeDeclaration((PsiClass)declaredElements[0]); |
| if (typeDeclaration instanceof Statement) { |
| return (Statement)typeDeclaration; |
| } |
| throw new UnsupportedOperationException("Non-statement type declaration: " + statement); |
| } |
| |
| VariableDeclaration declaration = new VariableDeclaration(); |
| bind(declaration, statement); |
| VariableDefinition definition = toVariableDefinition(statement, declaredElements); |
| declaration.astDefinition(definition); |
| |
| return declaration; |
| } |
| |
| @NonNull |
| private static VariableDefinition toVariableDefinition(@NonNull PsiDeclarationStatement statement, |
| @NonNull PsiElement[] declaredElements) { |
| VariableDefinition definition = new VariableDefinition(); |
| bind(definition, statement); |
| |
| Modifiers modifiers = null; |
| for (PsiElement element : declaredElements) { |
| if (element instanceof PsiVariable) { |
| PsiVariable variable = (PsiVariable)element; |
| if (modifiers == null) { |
| PsiModifierList modifierList = variable.getModifierList(); |
| if (modifierList != null) { |
| modifiers = toModifiers(modifierList); |
| } |
| } |
| PsiTypeElement typeElement = variable.getTypeElement(); |
| if (typeElement != null) { |
| definition.astTypeReference(toTypeReference(typeElement)); |
| } |
| VariableDefinitionEntry entry = toVariableDefinitionEntry(variable); |
| definition.astVariables().addToEnd(entry); |
| } else { |
| throw new UnsupportedOperationException("Not yet supporting variable declarations for " + element); |
| } |
| } |
| |
| if (modifiers != null) { |
| definition.astModifiers(modifiers); |
| } |
| |
| return definition; |
| } |
| |
| @NonNull |
| private static VariableDeclaration toVariableDeclaration(@NonNull PsiVariable variable) { |
| VariableDeclaration declaration = new VariableDeclaration(); |
| bind(declaration, variable); |
| |
| VariableDefinition definition = toVariableDefinition(variable); |
| bind(definition, variable); |
| declaration.astDefinition(definition); |
| |
| return declaration; |
| } |
| |
| @NonNull |
| private static ConstructorDeclaration toConstructorDeclaration(@NonNull PsiMethod method) { |
| assert method.isConstructor(); |
| ConstructorDeclaration m = new ConstructorDeclaration(); |
| bind(m, method); |
| PsiIdentifier nameIdentifier = method.getNameIdentifier(); |
| if (nameIdentifier != null) { |
| m.astTypeName(toIdentifier(nameIdentifier)); |
| } |
| m.astModifiers(toModifiers(method.getModifierList())); |
| for (PsiJavaCodeReferenceElement reference : method.getThrowsList().getReferenceElements()) { |
| m.astThrownTypeReferences().addToEnd(toTypeReference(reference)); |
| } |
| |
| StrictListAccessor<VariableDefinition, ConstructorDeclaration> parameters = m.astParameters(); |
| for (PsiParameter parameter : method.getParameterList().getParameters()) { |
| VariableDefinition definition = toVariableDefinition(parameter); |
| parameters.addToEnd(definition); |
| } |
| |
| PsiCodeBlock body = method.getBody(); |
| if (body != null) { |
| m.astBody(toBlock(body)); |
| } |
| |
| return m; |
| } |
| |
| @NonNull |
| private static MethodDeclaration toMethodDeclaration(@NonNull PsiMethod method) { |
| assert !method.isConstructor(); |
| MethodDeclaration m = new MethodDeclaration(); |
| bind(m, method); |
| |
| PsiIdentifier nameIdentifier = method.getNameIdentifier(); |
| if (nameIdentifier != null) { |
| m.astMethodName(toIdentifier(nameIdentifier)); |
| } |
| m.astModifiers(toModifiers(method.getModifierList())); |
| PsiTypeElement returnTypeElement = method.getReturnTypeElement(); |
| if (returnTypeElement != null) { |
| m.astReturnTypeReference(toTypeReference(returnTypeElement)); |
| } |
| for (PsiJavaCodeReferenceElement reference : method.getThrowsList().getReferenceElements()) { |
| m.astThrownTypeReferences().addToEnd(toTypeReference(reference)); |
| } |
| |
| StrictListAccessor<VariableDefinition, MethodDeclaration> parameters = m.astParameters(); |
| for (PsiParameter parameter : method.getParameterList().getParameters()) { |
| VariableDefinition definition = toVariableDefinition(parameter); |
| parameters.addToEnd(definition); |
| } |
| |
| PsiCodeBlock body = method.getBody(); |
| if (body != null) { |
| m.astBody(toBlock(body)); |
| } |
| |
| return m; |
| } |
| } |