001/* 002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others 003 * 004 * This program and the accompanying materials are made available under the 005 * terms of the Eclipse Public License 2.0 which is available at 006 * http://www.eclipse.org/legal/epl-2.0. 007 * 008 * SPDX-License-Identifier: EPL-2.0 009 */ 010 011package org.eclipse.golo.doc; 012 013import org.eclipse.golo.compiler.GoloCompiler; 014import org.eclipse.golo.compiler.PackageAndClass; 015import gololang.ir.*; 016 017import java.util.*; 018 019public class ModuleDocumentation implements DocumentationElement { 020 021 private String sourceFile; 022 private PackageAndClass moduleName; 023 private int moduleDefLine; 024 private String moduleDocumentation; 025 026 private final Map<String, Integer> imports = new TreeMap<>(); 027 private final Map<String, Integer> moduleStates = new TreeMap<>(); 028 private final SortedSet<FunctionDocumentation> functions = new TreeSet<>(); 029 private final Map<String, AugmentationDocumentation> augmentations = new TreeMap<>(); 030 private final SortedSet<StructDocumentation> structs = new TreeSet<>(); 031 private final SortedSet<UnionDocumentation> unions = new TreeSet<>(); 032 private final Set<NamedAugmentationDocumentation> namedAugmentations = new TreeSet<>(); 033 034 /** 035 * {@inheritDoc} 036 */ 037 @Override 038 public String type() { 039 return "module"; 040 } 041 042 ModuleDocumentation(GoloModule module) { 043 module.accept(new ModuleVisitor()); 044 } 045 046 ModuleDocumentation() { 047 048 } 049 050 public static ModuleDocumentation load(String filename, GoloCompiler compiler) throws java.io.IOException { 051 return new ModuleDocumentation(compiler.transform(compiler.parse(filename))); 052 } 053 054 public static ModuleDocumentation empty(String name) { 055 if (name == null || name.trim().isEmpty()) { 056 throw new IllegalArgumentException("Can't create empty module documentation without name"); 057 } 058 ModuleDocumentation doc = new ModuleDocumentation(); 059 doc.moduleName = PackageAndClass.of(name); 060 return doc; 061 } 062 063 public boolean isEmpty() { 064 return moduleStates.isEmpty() 065 && functions.isEmpty() 066 && augmentations.isEmpty() 067 && structs.isEmpty() 068 && unions.isEmpty() 069 && namedAugmentations.isEmpty(); 070 } 071 072 public String goloVersion() { 073 return org.eclipse.golo.cli.command.Metadata.VERSION; 074 } 075 076 public SortedSet<StructDocumentation> structs() { 077 return structs; 078 } 079 080 public SortedSet<UnionDocumentation> unions() { 081 return unions; 082 } 083 084 public SortedSet<FunctionDocumentation> functions() { 085 return functions(false); 086 } 087 088 public SortedSet<FunctionDocumentation> functions(boolean withLocal) { 089 if (withLocal) { 090 return functions; 091 } 092 TreeSet<FunctionDocumentation> pubFunctions = new TreeSet<>(); 093 for (FunctionDocumentation f : functions) { 094 if (!f.local()) { 095 pubFunctions.add(f); 096 } 097 } 098 return pubFunctions; 099 } 100 101 public String sourceFile() { 102 return this.sourceFile; 103 } 104 105 public String moduleName() { 106 return moduleName.toString(); 107 } 108 109 public String packageName() { 110 return moduleName.packageName(); 111 } 112 113 /** 114 * {@inheritDoc} 115 */ 116 @Override 117 public String label() { 118 return moduleName.toString(); 119 } 120 121 /** 122 * {@inheritDoc} 123 */ 124 @Override 125 public String name() { 126 return moduleName.className(); 127 } 128 129 /** 130 * {@inheritDoc} 131 */ 132 @Override 133 public String fullName() { 134 return moduleName.toString(); 135 } 136 137 /** 138 * {@inheritDoc} 139 */ 140 @Override 141 public String id() { 142 return ""; 143 } 144 145 /** 146 * {@inheritDoc} 147 */ 148 @Override 149 public DocumentationElement parent() { 150 return this; 151 } 152 153 public int moduleDefLine() { 154 return moduleDefLine; 155 } 156 157 /** 158 * {@inheritDoc} 159 */ 160 @Override 161 public int line() { 162 return moduleDefLine; 163 } 164 165 public String moduleDocumentation() { 166 return (moduleDocumentation != null) ? moduleDocumentation : "\n"; 167 } 168 169 public ModuleDocumentation moduleDocumentation(String doc) { 170 this.moduleDocumentation = doc; 171 return this; 172 } 173 174 /** 175 * {@inheritDoc} 176 */ 177 @Override 178 public String documentation() { 179 return moduleDocumentation(); 180 } 181 182 public Map<String, Integer> moduleStates() { 183 return moduleStates; 184 } 185 186 public Collection<AugmentationDocumentation> augmentations() { 187 return augmentations.values(); 188 } 189 190 public Collection<NamedAugmentationDocumentation> namedAugmentations() { 191 return namedAugmentations; 192 } 193 194 public Map<String, Integer> imports() { 195 return imports; 196 } 197 198 private class ModuleVisitor implements GoloIrVisitor { 199 200 private final Deque<Set<FunctionDocumentation>> functionContext = new LinkedList<>(); 201 private UnionDocumentation currentUnion; 202 private MemberHolder currentMemberHolder; 203 private final Deque<DocumentationElement> parents = new LinkedList<>(); 204 205 @Override 206 public void visitModule(GoloModule module) { 207 functionContext.push(functions); 208 parents.push(ModuleDocumentation.this); 209 moduleName = module.getPackageAndClass(); 210 moduleDefLine = module.positionInSourceCode().getStartLine(); 211 moduleDocumentation = module.documentation(); 212 sourceFile = module.sourceFile(); 213 module.walk(this); 214 } 215 216 @Override 217 public void visitModuleImport(ModuleImport moduleImport) { 218 if (!moduleImport.isImplicit()) { 219 imports.put(moduleImport.getPackageAndClass().toString(), moduleImport.positionInSourceCode().getStartLine()); 220 } 221 } 222 223 @Override 224 public void visitStruct(Struct struct) { 225 StructDocumentation doc = new StructDocumentation() 226 .parent(parents.peek()) 227 .name(struct.getName()) 228 .documentation(struct.documentation()) 229 .line(struct.positionInSourceCode().getStartLine()); 230 structs.add(doc); 231 currentMemberHolder = doc; 232 parents.push(doc); 233 struct.walk(this); 234 parents.pop(); 235 currentMemberHolder = null; 236 } 237 238 @Override 239 public void visitUnion(Union union) { 240 this.currentUnion = new UnionDocumentation() 241 .parent(parents.peek()) 242 .name(union.getName()) 243 .documentation(union.documentation()) 244 .line(union.positionInSourceCode().getStartLine()); 245 unions.add(this.currentUnion); 246 parents.push(currentUnion); 247 union.walk(this); 248 parents.pop(); 249 } 250 251 @Override 252 public void visitUnionValue(UnionValue value) { 253 UnionDocumentation.UnionValueDocumentation doc = this.currentUnion.addValue(value.getName()) 254 .parent(parents.peek()) 255 .documentation(value.documentation()) 256 .line(value.positionInSourceCode().getStartLine()); 257 currentMemberHolder = doc; 258 parents.push(doc); 259 value.walk(this); 260 parents.pop(); 261 currentMemberHolder = null; 262 } 263 264 @Override 265 public void visitAugmentation(Augmentation augment) { 266 String target = augment.getTarget().toString(); 267 if (!augmentations.containsKey(target)) { 268 augmentations.put(target, new AugmentationDocumentation() 269 .target(target) 270 .parent(parents.peek()) 271 .augmentationNames(augment.getNames()) 272 .line(augment.positionInSourceCode().getStartLine()) 273 ); 274 } 275 AugmentationDocumentation ad = augmentations.get(target); 276 if (augment.documentation() != null && !augment.documentation().isEmpty()) { 277 ad.documentation(String.join("\n", ad.documentation(), augment.documentation())); 278 } 279 functionContext.push(ad); 280 parents.push(ad); 281 augment.walk(this); 282 functionContext.pop(); 283 parents.pop(); 284 } 285 286 @Override 287 public void visitNamedAugmentation(NamedAugmentation augment) { 288 NamedAugmentationDocumentation augmentDoc = new NamedAugmentationDocumentation() 289 .parent(parents.peek()) 290 .name(augment.getName()) 291 .documentation(augment.documentation()) 292 .line(augment.positionInSourceCode().getStartLine()); 293 namedAugmentations.add(augmentDoc); 294 functionContext.push(augmentDoc); 295 parents.push(augmentDoc); 296 augment.walk(this); 297 functionContext.pop(); 298 parents.pop(); 299 } 300 301 @Override 302 public void visitFunction(GoloFunction function) { 303 if (!GoloModule.MODULE_INITIALIZER_FUNCTION.equals(function.getName())) { 304 functionContext.peek().add(new FunctionDocumentation() 305 .parent(parents.peek()) 306 .name(function.getName()) 307 .documentation(function.documentation()) 308 .augmentation(function.isInAugment()) 309 .line(function.positionInSourceCode().getStartLine()) 310 .local(function.isLocal()) 311 .arguments(function.getParameterNames()) 312 .varargs(function.isVarargs())); 313 } 314 } 315 316 @Override 317 public void visitLocalReference(LocalReference localRef) { 318 if (localRef.isModuleState()) { 319 moduleStates.put(localRef.getName(), localRef.positionInSourceCode().getStartLine()); 320 } 321 } 322 323 @Override 324 public void visitMember(Member member) { 325 currentMemberHolder.addMember(member.getName()) 326 .parent(parents.peek()) 327 .documentation(member.documentation()) 328 .line(member.positionInSourceCode().getStartLine()); 329 } 330 331 @Override 332 public void visitDecorator(Decorator decorator) { 333 } 334 335 @Override 336 public void visitBlock(Block block) { 337 } 338 339 @Override 340 public void visitConstantStatement(ConstantStatement constantStatement) { 341 } 342 343 @Override 344 public void visitReturnStatement(ReturnStatement returnStatement) { 345 } 346 347 @Override 348 public void visitFunctionInvocation(FunctionInvocation functionInvocation) { 349 } 350 351 @Override 352 public void visitMethodInvocation(MethodInvocation methodInvocation) { 353 } 354 355 @Override 356 public void visitAssignmentStatement(AssignmentStatement assignmentStatement) { 357 } 358 359 @Override 360 public void visitDestructuringAssignment(DestructuringAssignment assignment) { 361 } 362 363 @Override 364 public void visitReferenceLookup(ReferenceLookup referenceLookup) { 365 } 366 367 @Override 368 public void visitConditionalBranching(ConditionalBranching conditionalBranching) { 369 } 370 371 @Override 372 public void visitBinaryOperation(BinaryOperation binaryOperation) { 373 } 374 375 @Override 376 public void visitUnaryOperation(UnaryOperation unaryOperation) { 377 } 378 379 @Override 380 public void visitLoopStatement(LoopStatement loopStatement) { 381 } 382 383 @Override 384 public void visitForEachLoopStatement(ForEachLoopStatement foreachStatement) { 385 } 386 387 @Override 388 public void visitCaseStatement(CaseStatement caseStatement) { 389 } 390 391 @Override 392 public void visitMatchExpression(MatchExpression matchExpression) { 393 } 394 395 @Override 396 public void visitWhenClause(WhenClause<?> whenClause) { 397 } 398 399 @Override 400 public void visitThrowStatement(ThrowStatement throwStatement) { 401 } 402 403 @Override 404 public void visitTryCatchFinally(TryCatchFinally tryCatchFinally) { 405 } 406 407 @Override 408 public void visitClosureReference(ClosureReference closureReference) { 409 } 410 411 @Override 412 public void visitLoopBreakFlowStatement(LoopBreakFlowStatement loopBreakFlowStatement) { 413 } 414 415 @Override 416 public void visitCollectionLiteral(CollectionLiteral collectionLiteral) { 417 } 418 419 @Override 420 public void visitCollectionComprehension(CollectionComprehension collectionComprehension) { 421 } 422 423 @Override 424 public void visitNamedArgument(NamedArgument namedArgument) { 425 } 426 427 @Override 428 public void visitNoop(Noop noop) { 429 } 430 431 @Override 432 public void visitToplevelElements(ToplevelElements toplevels) { 433 toplevels.walk(this); 434 } 435 } 436}