1+ /**
2+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
3+ * and/or other contributors as indicated by the @authors tag. See the
4+ * copyright.txt file in the distribution for a full listing of all
5+ * contributors.
6+ *
7+ * Licensed under the Apache License, Version 2.0 (the "License");
8+ * you may not use this file except in compliance with the License.
9+ * You may obtain a copy of the License at
10+ *
11+ * http://www.apache.org/licenses/LICENSE-2.0
12+ *
13+ * Unless required by applicable law or agreed to in writing, software
14+ * distributed under the License is distributed on an "AS IS" BASIS,
15+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+ * See the License for the specific language governing permissions and
17+ * limitations under the License.
18+ */
19+ package org .mapstruct .eclipse .internal .quickfix ;
20+
21+ import java .util .Iterator ;
22+
23+ import org .eclipse .core .resources .IMarker ;
24+ import org .eclipse .core .resources .IResource ;
25+ import org .eclipse .core .runtime .CoreException ;
26+ import org .eclipse .jdt .core .ICompilationUnit ;
27+ import org .eclipse .jdt .core .IJavaElement ;
28+ import org .eclipse .jdt .core .JavaCore ;
29+ import org .eclipse .jdt .core .dom .AST ;
30+ import org .eclipse .jdt .core .dom .ASTNode ;
31+ import org .eclipse .jdt .core .dom .CompilationUnit ;
32+ import org .eclipse .jdt .core .dom .ImportDeclaration ;
33+ import org .eclipse .jdt .core .dom .rewrite .ASTRewrite ;
34+ import org .eclipse .jdt .internal .ui .JavaPlugin ;
35+ import org .eclipse .jdt .internal .ui .JavaPluginImages ;
36+ import org .eclipse .jdt .internal .ui .javaeditor .EditorUtility ;
37+ import org .eclipse .jdt .internal .ui .text .correction .ASTResolving ;
38+ import org .eclipse .jdt .ui .SharedASTProvider ;
39+ import org .eclipse .jface .text .Position ;
40+ import org .eclipse .jface .text .source .Annotation ;
41+ import org .eclipse .jface .text .source .IAnnotationModel ;
42+ import org .eclipse .swt .graphics .Image ;
43+ import org .eclipse .ui .IEditorInput ;
44+ import org .eclipse .ui .IMarkerResolution2 ;
45+ import org .eclipse .ui .texteditor .MarkerAnnotation ;
46+ import org .mapstruct .eclipse .internal .quickfix .visitors .FindMethodByPositionVisitor ;
47+
48+ /**
49+ * Base class for quick fixes
50+ *
51+ * @author Andreas Gudian
52+ */
53+ @ SuppressWarnings ("restriction" )
54+ public abstract class MapStructQuickFix implements IMarkerResolution2 {
55+ private String label ;
56+
57+ protected MapStructQuickFix (String label ) {
58+ this .label = label ;
59+ }
60+
61+ @ Override
62+ public String getLabel () {
63+ return label ;
64+ }
65+
66+ @ Override
67+ public void run (IMarker marker ) {
68+ ICompilationUnit compilationUnit = null ;
69+ try {
70+ IResource resource = marker .getResource ();
71+ IJavaElement javaElement = JavaCore .create ( resource );
72+
73+ compilationUnit = (ICompilationUnit ) javaElement .getAdapter ( ICompilationUnit .class );
74+ IEditorInput input = EditorUtility .getEditorInput ( compilationUnit );
75+ if ( input != null ) {
76+ CompilationUnit astCompilationUnit = toAST ( compilationUnit );
77+
78+ ASTNode locatedNode =
79+ locateASTNodeForSartingOffset ( findProblemStart ( input , marker ), astCompilationUnit );
80+ if ( locatedNode != null ) {
81+ ASTRewrite rewrite = getASTRewrite ( astCompilationUnit , locatedNode , marker );
82+
83+ if ( rewrite != null ) {
84+ compilationUnit .applyTextEdit ( rewrite .rewriteAST (), null );
85+ compilationUnit .becomeWorkingCopy ( null );
86+ compilationUnit .commitWorkingCopy ( true , null );
87+ compilationUnit .discardWorkingCopy ();
88+ marker .delete ();
89+ }
90+ }
91+ }
92+ }
93+ catch ( CoreException e ) {
94+ throw new RuntimeException ( e );
95+ }
96+ }
97+
98+ /**
99+ * @param input editor input
100+ * @param marker the marker
101+ * @return the offset of the problem, either as currently computed in an open (dirty) editor, or as originally
102+ * stated in the marker
103+ * @throws CoreException
104+ */
105+ @ SuppressWarnings ("unchecked" )
106+ private static int findProblemStart (IEditorInput input , IMarker marker ) throws CoreException {
107+ IAnnotationModel model =
108+ JavaPlugin .getDefault ().getCompilationUnitDocumentProvider ().getAnnotationModel ( input );
109+ if ( model != null ) {
110+ Iterator <Annotation > iter = model .getAnnotationIterator ();
111+
112+ while ( iter .hasNext () ) {
113+ Annotation curr = iter .next ();
114+ if ( curr instanceof MarkerAnnotation ) {
115+ MarkerAnnotation annot = (MarkerAnnotation ) curr ;
116+ if ( marker .equals ( annot .getMarker () ) ) {
117+ Position pos = model .getPosition ( annot );
118+ if ( pos != null ) {
119+ return pos .getOffset ();
120+ }
121+ }
122+ }
123+ }
124+ }
125+
126+ Integer charStart = (Integer ) marker .getAttribute ( IMarker .CHAR_START );
127+
128+ return charStart != null ? charStart : -1 ;
129+ }
130+
131+ private ASTNode locateASTNodeForSartingOffset (int problemOffset , CompilationUnit astCompilationUnit )
132+ throws CoreException {
133+ FindMethodByPositionVisitor visitor = new FindMethodByPositionVisitor ( problemOffset );
134+ astCompilationUnit .accept ( visitor );
135+ return visitor .getLocatedNode ();
136+ }
137+
138+ /**
139+ * @param unit the compilation unit
140+ * @param nodeWithMarker the ASTNode that is located at the start position of the marker
141+ * @param marker the marker
142+ * @return the rewrite to be performed, or <code>null</code> in case no changes are to be performed
143+ */
144+ protected abstract ASTRewrite getASTRewrite (CompilationUnit unit , ASTNode nodeWithMarker , IMarker marker );
145+
146+ /**
147+ * Add an import statement for the fullyQualifiedName if it is not yet imported
148+ *
149+ * @param compilationUnit the compilation unit
150+ * @param rewrite the rewrite to modify
151+ * @param fullyQualifiedName the fully qualified name of the type to add an import for
152+ */
153+ protected void addImportIfRequired (CompilationUnit compilationUnit , ASTRewrite rewrite , String fullyQualifiedName ) {
154+ if ( !hasImport ( compilationUnit , fullyQualifiedName ) ) {
155+ AST ast = compilationUnit .getAST ();
156+ ImportDeclaration declaration = ast .newImportDeclaration ();
157+ declaration .setName ( ast .newName ( fullyQualifiedName ) );
158+
159+ rewrite .getListRewrite ( compilationUnit , CompilationUnit .IMPORTS_PROPERTY ).insertLast ( declaration , null );
160+ }
161+ }
162+
163+ private static boolean hasImport (CompilationUnit compilationUnit , String fullyQualifiedName ) {
164+ for ( Object obj : compilationUnit .imports () ) {
165+ ImportDeclaration importDec = (ImportDeclaration ) obj ;
166+ if ( importDec .getName ().getFullyQualifiedName ().equals ( fullyQualifiedName ) ) {
167+ return true ;
168+ }
169+ }
170+ return false ;
171+ }
172+
173+ @ Override
174+ public String getDescription () {
175+ return null ;
176+ }
177+
178+ @ Override
179+ public Image getImage () {
180+ return JavaPluginImages .get ( JavaPluginImages .IMG_CORRECTION_CHANGE );
181+ }
182+
183+ public abstract boolean canFix (IMarker marker );
184+
185+ /**
186+ * @param marker the marker
187+ * @return the message of the marker, or an empty string in case the message cannot be retrieved
188+ */
189+ protected static String getMessage (IMarker marker ) {
190+ try {
191+ return (String ) marker .getAttribute ( IMarker .MESSAGE );
192+ }
193+ catch ( CoreException e ) {
194+ return "" ;
195+ }
196+ }
197+
198+ private static CompilationUnit toAST (ICompilationUnit unit ) {
199+ CompilationUnit astRoot = SharedASTProvider .getAST ( unit , SharedASTProvider .WAIT_YES , null );
200+ if ( astRoot == null ) {
201+ astRoot = ASTResolving .createQuickFixAST ( unit , null );
202+ }
203+ return astRoot ;
204+ }
205+ }
0 commit comments