Skip to content

Commit 5b0fdde

Browse files
committed
... I S S U E # 9 9 9 : Add classes to support Objective-C analysis
Also, make H extension matching imprecise but with definite C fallback.
1 parent 53bdaa8 commit 5b0fdde

37 files changed

+3069
-36
lines changed

build.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ Portions Copyright (c) 2017-2018, Chris Fraire <[email protected]>.
303303
<run-jflex dir="${gen.analysis.dir}/javascript" name="JavaScriptXref"/>
304304
<run-jflex dir="${gen.analysis.dir}/lua" name="LuaSymbolTokenizer"/>
305305
<run-jflex dir="${gen.analysis.dir}/lua" name="LuaXref"/>
306+
<run-jflex dir="${gen.analysis.dir}/objectivec" name="ObjectiveCLexer"/>
307+
<run-jflex dir="${gen.analysis.dir}/objectivec" name="ObjectiveCNamer"/>
306308
<run-jflex dir="${gen.analysis.dir}/powershell" name="PowershellSymbolTokenizer"/>
307309
<run-jflex dir="${gen.analysis.dir}/powershell" name="PowershellXref"/>
308310
<run-jflex dir="${gen.analysis.dir}/python" name="PythonSymbolTokenizer"/>

src/org/opensolaris/opengrok/analysis/AnalyzerGuru.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
import org.opensolaris.opengrok.analysis.clojure.ClojureAnalyzerFactory;
9898
import org.opensolaris.opengrok.analysis.json.JsonAnalyzerFactory;
9999
import org.opensolaris.opengrok.analysis.kotlin.KotlinAnalyzerFactory;
100+
import org.opensolaris.opengrok.analysis.objectivec.ObjectiveCAnalyzerFactory;
100101
import org.opensolaris.opengrok.analysis.sh.ShAnalyzerFactory;
101102
import org.opensolaris.opengrok.analysis.powershell.PowershellAnalyzerFactory;
102103
import org.opensolaris.opengrok.analysis.ruby.RubyAnalyzerFactory;
@@ -278,7 +279,8 @@ public AnalyzerGuru(RuntimeEnvironment env) {
278279
new JarAnalyzerFactory(env),
279280
new ZipAnalyzerFactory(env),
280281
new TarAnalyzerFactory(env),
281-
new CAnalyzerFactory(env),
282+
new ObjectiveCAnalyzerFactory(env), // Just before C.
283+
new CAnalyzerFactory(env), // Just after Objective-C.
282284
new CSharpAnalyzerFactory(env),
283285
new VBAnalyzerFactory(env),
284286
new CxxAnalyzerFactory(env),
@@ -344,15 +346,15 @@ public AnalyzerGuru(RuntimeEnvironment env) {
344346
* {@link FileAnalyzerFactory} subclasses are revised to target more or
345347
* different files.
346348
* @return a value whose lower 32-bits are a static value
347-
* 20180212_07
349+
* 20180214_00
348350
* for the current implementation and whose higher-32 bits are non-zero if
349351
* {@link #addExtension(java.lang.String, org.opensolaris.opengrok.analysis.FileAnalyzerFactory)}
350352
* or
351353
* {@link #addPrefix(java.lang.String, org.opensolaris.opengrok.analysis.FileAnalyzerFactory)}
352354
* has been called.
353355
*/
354356
public long getVersionNo() {
355-
final int ver32 = 20180212_07; // Edit comment above too!
357+
final int ver32 = 20180214_00; // Edit comment above too!
356358
long ver = ver32;
357359
if (customizationHashCode != 0) {
358360
ver |= (long)customizationHashCode << 32;

src/org/opensolaris/opengrok/analysis/Ctags.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.nio.charset.StandardCharsets;
3535
import java.util.ArrayList;
3636
import java.util.List;
37+
import java.util.function.Function;
3738
import java.util.logging.Level;
3839
import java.util.logging.Logger;
3940
import org.opensolaris.opengrok.configuration.RuntimeEnvironment;
@@ -52,6 +53,7 @@ public class Ctags implements Resettable {
5253

5354
private final RuntimeEnvironment env;
5455
private volatile boolean closing;
56+
private Function<String, String> matchReducer;
5557
private Process ctags;
5658
private Thread errThread;
5759
private OutputStreamWriter ctagsIn;
@@ -102,12 +104,29 @@ public void setCTagsExtraOptionsFile(String CTagsExtraOptionsFile) {
102104
this.CTagsExtraOptionsFile = CTagsExtraOptionsFile;
103105
}
104106

107+
/**
108+
* Sets a function that is used as a last resort to reduce the text that is
109+
* matched in searches against source text.
110+
* <p>
111+
* E.g., for Objective-C with multi-part method names that are interleaved
112+
* with parameter types and names, a reducer could lop off parts of the
113+
* method name for last-resort searching.
114+
* <p>
115+
* The reducer object can return {@code null} to indicate that no
116+
* last-resort search should be done.
117+
* @param obj a defined instance or {@code null}
118+
*/
119+
public void setMatchReducer(Function<String, String> obj) {
120+
matchReducer = obj;
121+
}
122+
105123
/**
106124
* Resets the instance for use for another file but without closing any
107125
* running ctags instance.
108126
*/
109127
@Override
110128
public void reset() {
129+
setMatchReducer(null);
111130
setTabSize(0);
112131
}
113132

@@ -393,6 +412,7 @@ public Definitions doCtags(String file) throws IOException,
393412
}
394413

395414
CtagsReader rdr = new CtagsReader();
415+
rdr.setMatchReducer(matchReducer);
396416
rdr.setSplitterSupplier(() -> { return trySplitSource(file); });
397417
rdr.setTabSize(tabSize);
398418
Definitions ret;
@@ -469,6 +489,7 @@ public void destroy() {
469489
};
470490

471491
CtagsReader rdr = new CtagsReader();
492+
rdr.setMatchReducer(matchReducer);
472493
rdr.setTabSize(tabSize);
473494
readTags(rdr);
474495
Definitions ret = rdr.getDefinitions();

src/org/opensolaris/opengrok/analysis/CtagsReader.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
package org.opensolaris.opengrok.analysis;
2626

2727
import java.util.EnumMap;
28+
import java.util.function.Function;
2829
import java.util.function.Supplier;
2930
import java.util.logging.Level;
3031
import java.util.logging.Logger;
@@ -91,6 +92,8 @@ public class CtagsReader {
9192
private boolean triedSplitterSupplier;
9293
private SourceSplitter splitter;
9394

95+
private Function<String, String> matchReducer;
96+
9497
private int tabSize;
9598

9699
/**
@@ -197,6 +200,22 @@ public void setSplitterSupplier(Supplier<SourceSplitter> obj) {
197200
splitterSupplier = obj;
198201
}
199202

203+
/**
204+
* Sets a function that is used as a last resort to reduce the text that is
205+
* matched in searches against source text.
206+
* <p>
207+
* E.g., for Objective-C with multi-part method names that are interleaved
208+
* with parameter types and names, a reducer could lop off parts of the
209+
* method name for last-resort searching.
210+
* <p>
211+
* The reducer object can return {@code null} to indicate that no
212+
* last-resort search should be done.
213+
* @param obj a defined instance or {@code null}
214+
*/
215+
public void setMatchReducer(Function<String, String> obj) {
216+
matchReducer = obj;
217+
}
218+
200219
/**
201220
* Reads a line into the instance's definitions.
202221
* @param tagLine a defined line or null to no-op
@@ -436,6 +455,13 @@ private CpatIndex bestIndexOfTag(int lineno, String whole, String str) {
436455
e = ExpandTabsReader.translate(whole, woff + str.length(), t);
437456
return new CpatIndex(lineno, s, e);
438457
}
458+
459+
if (matchReducer != null) {
460+
String newStr = matchReducer.apply(str);
461+
if (newStr != null && !newStr.equals(str)) {
462+
return bestIndexOfTag(lineno, origWhole, newStr);
463+
}
464+
}
439465
/**
440466
* When ctags has truncated a pattern, or when it spans multiple lines,
441467
* then `str' might not be found in `whole'. In that case, return an
@@ -543,6 +569,12 @@ private CpatIndex bestIndexOfArg(int lineno, String whole, String arg) {
543569
}
544570
}
545571

572+
if (matchReducer != null) {
573+
String newArg = matchReducer.apply(arg);
574+
if (newArg != null && !newArg.equals(arg)) {
575+
return bestIndexOfArg(lineno, whole, newArg);
576+
}
577+
}
546578
/**
547579
* When no match is found, return an imprecise index for the last
548580
* character as the best we can do.

src/org/opensolaris/opengrok/analysis/FileAnalyzer.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.io.StringReader;
3030
import java.io.Writer;
3131
import java.util.Locale;
32+
import java.util.function.Function;
3233
import java.util.logging.Level;
3334
import java.util.logging.Logger;
3435

@@ -155,6 +156,16 @@ protected int getSpecializedVersionNo() {
155156
return 0; // FileAnalyzer is not specialized.
156157
}
157158

159+
/**
160+
* Subclasses can override to return a function that is used as a last
161+
* resort to reduce the text that is matched in searches for ctags positions
162+
* w.r.t. source text.
163+
* @return {@code null}
164+
*/
165+
public Function<String, String> getMatchReducer() {
166+
return null;
167+
}
168+
158169
public void setCtags(Ctags ctags) {
159170
this.ctags = ctags;
160171
}

src/org/opensolaris/opengrok/analysis/JFlexSymbolMatcher.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,23 @@ protected void onSymbolMatched(String str, int start) {
126126
}
127127
}
128128

129+
/**
130+
* Raises
131+
* {@link SymbolMatchedListener#symbolMatched(org.opensolaris.opengrok.analysis.SymbolMatchedEvent)}
132+
* for a subscribed listener.
133+
* @param literal the literal representation of the symbol
134+
* @param str the symbol string
135+
* @param start the symbol literal start position
136+
*/
137+
protected void onSymbolMatched(String literal, String str, int start) {
138+
SymbolMatchedListener l = symbolListener;
139+
if (l != null) {
140+
SymbolMatchedEvent evt = new SymbolMatchedEvent(this, literal, str,
141+
start, start + literal.length());
142+
l.symbolMatched(evt);
143+
}
144+
}
145+
129146
/**
130147
* Raises
131148
* {@link SymbolMatchedListener#sourceCodeSeen(org.opensolaris.opengrok.analysis.SourceCodeSeenEvent)}

src/org/opensolaris/opengrok/analysis/JFlexXref.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ public void setFoldingEnabled(boolean foldingEnabled) {
210210
public void symbolMatched(SymbolMatchedEvent evt) {
211211
try {
212212
JFlexXrefUtils.writeSymbol(out, defs, urlPrefix, project,
213-
evt.getStr(), null, matcher.getLineNumber(), false, false);
213+
evt.getLiteral(), evt.getStr(), null, matcher.getLineNumber(),
214+
false, false);
214215
} catch (IOException ex) {
215216
throw new RuntimeException(ex);
216217
}

src/org/opensolaris/opengrok/analysis/JFlexXrefUtils.java

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,11 @@ public static void writeEMailAddress(Writer out, String address,
222222
}
223223

224224
/**
225-
* Writes a symbol and generate links as appropriate.
225+
* Calls
226+
* {@link #writeSymbol(java.io.Writer, org.opensolaris.opengrok.analysis.Definitions, java.lang.String, org.opensolaris.opengrok.configuration.Project, java.lang.String, java.lang.String, java.util.Set, int, boolean, boolean)}
227+
* with {@code out}, {@code defs}, {@code urlPrefix}, {@code project},
228+
* {@code symbol} (twice), {@code keywords}, {@code line},
229+
* {@code caseSensitive}, and {@code isKeyword}.
226230
*
227231
* @param out a defined, target instance
228232
* @param defs a possibly defined instance or null
@@ -241,16 +245,43 @@ public static void writeEMailAddress(Writer out, String address,
241245
*/
242246
public static boolean writeSymbol(Writer out, Definitions defs,
243247
String urlPrefix, Project project, String symbol, Set<String> keywords,
244-
int line, boolean caseSensitive, boolean isKeyword)
245-
throws IOException {
248+
int line, boolean caseSensitive, boolean isKeyword) throws IOException {
249+
250+
return writeSymbol(out, defs, urlPrefix, project, symbol, symbol,
251+
keywords, line, caseSensitive, isKeyword);
252+
}
253+
254+
/**
255+
* Writes a symbol and generate links as appropriate.
256+
*
257+
* @param out a defined, target instance
258+
* @param defs a possibly defined instance or null
259+
* @param urlPrefix a defined instance
260+
* @param project a possibly defined instance or null
261+
* @param literal the literal representation of the symbol
262+
* @param symbol the symbol to write
263+
* @param keywords a set of keywords recognized by this analyzer (no links
264+
* will be generated if the symbol is a keyword)
265+
* @param line the line number on which the symbol appears
266+
* @param caseSensitive Whether the keyword list is case sensitive
267+
* @param isKeyword Whether the symbol is certainly a keyword without
268+
* bothering to look up in a defined {@code keywords}
269+
* @return true if the {@code symbol} was not in {@code keywords} or if
270+
* {@code keywords} was null and if-and-only-if {@code isKeyword} is false
271+
* @throws IOException if an error occurs while writing to the stream
272+
*/
273+
public static boolean writeSymbol(Writer out, Definitions defs,
274+
String urlPrefix, Project project, String literal, String symbol,
275+
Set<String> keywords, int line, boolean caseSensitive,
276+
boolean isKeyword) throws IOException {
277+
246278
String[] strs = new String[1];
247279
strs[0] = "";
248-
249280
String check = caseSensitive ? symbol : symbol.toLowerCase(Locale.ROOT);
250281
if (isKeyword || (keywords != null && keywords.contains( check ))) {
251282
// This is a keyword, so we don't create a link.
252283
out.append("<b>");
253-
Util.htmlize(symbol, out);
284+
Util.htmlize(literal, out);
254285
out.append("</b>");
255286
return false;
256287
}
@@ -296,10 +327,10 @@ public static boolean writeSymbol(Writer out, Definitions defs,
296327
out.append(" intelliWindow-symbol\"");
297328
out.append(" data-definition-place=\"def\"");
298329
out.append(">");
299-
Util.htmlize(symbol, out);
330+
Util.htmlize(literal, out);
300331
out.append("</a>");
301332
} else if (defs != null && defs.occurrences(symbol) == 1) {
302-
writeSameFileLinkSymbol(out, symbol);
333+
writeSameFileLinkSymbol(out, literal, symbol);
303334
} else {
304335
// This is a symbol that is not defined in this file, or a symbol
305336
// that is defined more than once in this file. In either case, we
@@ -314,22 +345,37 @@ public static boolean writeSymbol(Writer out, Definitions defs,
314345
out.append(" class=\"intelliWindow-symbol\"");
315346
out.append(" data-definition-place=\"undefined-in-file\"");
316347
out.append(">");
317-
Util.htmlize(symbol, out);
348+
Util.htmlize(literal, out);
318349
out.append("</a>");
319350
}
320351
return true;
321352
}
322353

323354
/**
324-
* Write a symbol with a link to its definition which is expected at
325-
* exactly one location in the same file.
355+
* Calls
356+
* {@link #writeSameFileLinkSymbol(java.io.Writer, java.lang.String, java.lang.String)}
357+
* with {@code out} and {@code symbol} (twice).
326358
* @param out a defined, target instance
327359
* @param symbol the symbol to write
328360
* @throws IOException if {@link Writer#append(java.lang.CharSequence)}
329361
* fails
330362
*/
331363
public static void writeSameFileLinkSymbol(Writer out, String symbol)
332364
throws IOException {
365+
writeSameFileLinkSymbol(out, symbol, symbol);
366+
}
367+
368+
/**
369+
* Write a symbol with a link to its definition which is expected at
370+
* exactly one location in the same file.
371+
* @param out a defined, target instance
372+
* @param literal the literal representation of the symbol
373+
* @param symbol the symbol to write
374+
* @throws IOException if {@link Writer#append(java.lang.CharSequence)}
375+
* fails
376+
*/
377+
public static void writeSameFileLinkSymbol(Writer out, String literal,
378+
String symbol) throws IOException {
333379
// This is a reference to a symbol defined exactly once in this file.
334380
String style_class = "d";
335381

@@ -341,7 +387,7 @@ public static void writeSameFileLinkSymbol(Writer out, String symbol)
341387
out.append("\"");
342388
out.append(" data-definition-place=\"defined-in-file\"");
343389
out.append(">");
344-
Util.htmlize(symbol, out);
390+
Util.htmlize(literal, out);
345391
out.append("</a>");
346392
}
347393

0 commit comments

Comments
 (0)