package com.redhat.ceylon.eclipse.code.correct; import java.util.Collection; import org.eclipse.core.resources.IFile; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.TextFileChange; import org.eclipse.text.edits.InsertEdit; import com.redhat.ceylon.compiler.typechecker.tree.Tree; import com.redhat.ceylon.ide.common.util.FindContainerVisitor; import com.redhat.ceylon.model.typechecker.model.Declaration; import com.redhat.ceylon.model.typechecker.model.Type; import com.redhat.ceylon.model.typechecker.model.TypeDeclaration; public class AddThrowsAnnotationProposal extends CorrectionProposal { public static void addThrowsAnnotationProposal(Collection<ICompletionProposal> proposals, Tree.Statement statement, Tree.CompilationUnit cu, IFile file, IDocument doc) { Type exceptionType = determineExceptionType(statement); if (exceptionType == null) { return; } Tree.Declaration throwContainer = determineThrowContainer(statement, cu); if( !(throwContainer instanceof Tree.MethodDefinition) && !(throwContainer instanceof Tree.AttributeGetterDefinition) && !(throwContainer instanceof Tree.AttributeSetterDefinition) && !(throwContainer instanceof Tree.ClassOrInterface) ) { return; } if (isAlreadyPresent(throwContainer, exceptionType)) { return; } String throwsAnnotation = "throws (`class " + exceptionType.asString() + "`, \"\")"; InsertEdit throwsAnnotationInsertEdit = new correctJ2C().addAnnotationsQuickFix() .createInsertAnnotationEdit(throwsAnnotation, throwContainer, doc); TextFileChange throwsAnnotationChange = new TextFileChange("Add Throws Annotation", file); throwsAnnotationChange.setEdit(throwsAnnotationInsertEdit); int cursorOffset = throwsAnnotationInsertEdit.getOffset() + throwsAnnotationInsertEdit.getText().indexOf(")") - 1; AddThrowsAnnotationProposal proposal = new AddThrowsAnnotationProposal(throwsAnnotationChange, exceptionType, cursorOffset, throwContainer.getIdentifier() != null ? throwContainer.getIdentifier().getText() : ""); if (!proposals.contains(proposal)) { proposals.add(proposal); } } private static Type determineExceptionType(Tree.Statement statement) { Type exceptionType = null; if (statement instanceof Tree.Throw) { Type ceylonLangExceptionType = statement.getUnit().getExceptionDeclaration().getType(); Tree.Expression throwExpression = ((Tree.Throw) statement).getExpression(); if (throwExpression == null) { exceptionType = ceylonLangExceptionType; } else { Type throwExpressionType = throwExpression.getTypeModel(); if ( throwExpressionType != null && throwExpressionType.isSubtypeOf(ceylonLangExceptionType) ) { exceptionType = throwExpressionType; } } } return exceptionType; } private static Tree.Declaration determineThrowContainer(Tree.Statement statement, Tree.CompilationUnit cu) { FindContainerVisitor fcv = new FindContainerVisitor(statement); fcv.visit(cu); return fcv.getDeclaration(); } private static boolean isAlreadyPresent(Tree.Declaration throwContainer, Type exceptionType) { Tree.AnnotationList annotationList = throwContainer.getAnnotationList(); if (annotationList != null) { for (Tree.Annotation annotation : annotationList.getAnnotations()) { ceylon.language.String str = new correctJ2C().addAnnotationsQuickFix() .getAnnotationIdentifier(annotation); String annotationIdentifier = str == null ? null : str.value; if ("throws".equals(annotationIdentifier)) { Tree.PositionalArgumentList positionalArgumentList = annotation.getPositionalArgumentList(); if (positionalArgumentList != null && positionalArgumentList.getPositionalArguments() != null && positionalArgumentList.getPositionalArguments().size() > 0) { Tree.PositionalArgument throwsArg = positionalArgumentList.getPositionalArguments().get(0); if (throwsArg instanceof Tree.ListedArgument) { Tree.Expression throwsArgExp = ((Tree.ListedArgument) throwsArg).getExpression(); if (throwsArgExp != null) { Tree.Term term = throwsArgExp.getTerm(); if (term instanceof Tree.MemberOrTypeExpression) { Declaration declaration = ((Tree.MemberOrTypeExpression) term).getDeclaration(); if (declaration instanceof TypeDeclaration) { Type type = ((TypeDeclaration) declaration).getType(); if (exceptionType.isExactly(type)) { return true; } } } } } } } } } return false; } private AddThrowsAnnotationProposal(Change change, Type exceptionType, int offset, String declName) { super("Add throws annotation to '" + declName + "'", change, new Region(offset, 0)); } }