Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 95c2348edacf41e6984ad17e1bc07ad2671d6ab5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*******************************************************************************
 * Copyright (c) 2006, 2015 BEA Systems, Inc. 
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *    wharley@bea.com - initial API and implementation
 *    
 *******************************************************************************/

package org.eclipse.jdt.internal.compiler.apt.dispatch;

import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;

/**
 * Manages context during a single round of annotation processing.
 */
public class RoundDispatcher {
	
	private final Set<TypeElement> _unclaimedAnnotations;
	private final RoundEnvironment _roundEnv;
	private final IProcessorProvider _provider;
	private boolean _searchForStar = false;
	private final PrintWriter _traceProcessorInfo;
	private final PrintWriter _traceRounds;
	
	/**
	 * Processors discovered so far.  This list may grow during the
	 * course of a round, as additional processors are discovered.
	 */
	private final List<ProcessorInfo> _processors;
	
	/**
	 * @param rootAnnotations a possibly empty but non-null set of annotations on the
	 * root compilation units of this round.  A local copy of the set will be made, to
	 * avoid modifying the set passed in.
	 * @param traceProcessorInfo a PrintWriter that processor trace output will be sent 
	 * to, or null if tracing is not desired.
	 * @param traceRounds 
	 */
	public RoundDispatcher(
			IProcessorProvider provider, 
			RoundEnvironment env, 
			Set<TypeElement> rootAnnotations, 
			PrintWriter traceProcessorInfo, 
			PrintWriter traceRounds)
	{
		_provider = provider;
		_processors = provider.getDiscoveredProcessors();
		_roundEnv = env;
		_unclaimedAnnotations = new HashSet<>(rootAnnotations);
		_traceProcessorInfo = traceProcessorInfo;
		_traceRounds = traceRounds;
	}
	
	/**
	 * Handle a complete round, dispatching to all appropriate processors. 
	 */
	public void round()
	{
		if (null != _traceRounds) {
			StringBuilder sbElements = new StringBuilder();
			sbElements.append("\tinput files: {"); //$NON-NLS-1$
			Iterator<? extends Element> iElements = _roundEnv.getRootElements().iterator();
			boolean hasNext = iElements.hasNext();
			while (hasNext) {
				sbElements.append(iElements.next());
				hasNext = iElements.hasNext();
				if (hasNext) {
					sbElements.append(',');
				}
			}
			sbElements.append('}');
			_traceRounds.println(sbElements.toString());
			
			StringBuilder sbAnnots = new StringBuilder();
			sbAnnots.append("\tannotations: ["); //$NON-NLS-1$
			Iterator<TypeElement> iAnnots = _unclaimedAnnotations.iterator();
			hasNext = iAnnots.hasNext();
			while (hasNext) {
				sbAnnots.append(iAnnots.next());
				hasNext = iAnnots.hasNext();
				if (hasNext) {
					sbAnnots.append(',');
				}
			}
			sbAnnots.append(']');
			_traceRounds.println(sbAnnots.toString());
			
			_traceRounds.println("\tlast round: " + _roundEnv.processingOver()); //$NON-NLS-1$
		}
		
		// If there are no root annotations, try to find a processor that claims "*"
		_searchForStar = _unclaimedAnnotations.isEmpty();
		
		// Iterate over all the already-found processors, giving each one a chance at the unclaimed
		// annotations. If a processor is called at all, it is called on every subsequent round 
		// including the final round, but it may be called with an empty set of annotations.
		for (ProcessorInfo pi : _processors) {
			handleProcessor(pi);
		}
		
		// If there are any unclaimed annotations, or if there were no root annotations and
		// we have not yet run into a processor that claimed "*", continue discovery.
		while (_searchForStar || !_unclaimedAnnotations.isEmpty()) {
			ProcessorInfo pi = _provider.discoverNextProcessor();
			if (null == pi) {
				// There are no more processors to be discovered.
				break;
			}
			handleProcessor(pi);
		}
		
		// TODO: If !unclaimedAnnos.isEmpty(), issue a warning.
	}
	
	/**
	 * Evaluate a single processor.  Depending on the unclaimed annotations,
	 * the annotations this processor supports, and whether it has already been
	 * called in a previous round, possibly call its process() method.
	 */
	private void handleProcessor(ProcessorInfo pi)
	{
		try {
			Set<TypeElement> annotationsToProcess = new HashSet<>();
			boolean shouldCall = pi.computeSupportedAnnotations(
					_unclaimedAnnotations, annotationsToProcess);
			if (shouldCall) {
				boolean claimed = pi._processor.process(annotationsToProcess, _roundEnv);
				if (null != _traceProcessorInfo && !_roundEnv.processingOver()) {
					StringBuilder sb = new StringBuilder();
					sb.append("Processor "); //$NON-NLS-1$
					sb.append(pi._processor.getClass().getName());
					sb.append(" matches ["); //$NON-NLS-1$
					Iterator<TypeElement> i = annotationsToProcess.iterator();
					boolean hasNext = i.hasNext();
					while (hasNext) {
						sb.append(i.next());
						hasNext = i.hasNext();
						if (hasNext) {
							sb.append(' ');
						}
					}
					sb.append("] and returns "); //$NON-NLS-1$
					sb.append(claimed);
					_traceProcessorInfo.println(sb.toString());
				}
				if (claimed) {
					// The processor claimed its annotations.
					_unclaimedAnnotations.removeAll(annotationsToProcess);
					if (pi.supportsStar()) {
						_searchForStar = false;
					}
				}
			}
		} catch (Throwable e) {
			// If a processor throws an exception (as opposed to reporting an error),
			// report it and abort compilation by throwing AbortCompilation.
			_provider.reportProcessorException(pi._processor, new Exception(e));
		}
	}
	
}

Back to the top