• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.jetbrains.dokka.Samples
2 
3 import com.google.inject.Inject
4 import com.intellij.psi.PsiElement
5 import com.intellij.psi.PsiWhiteSpace
6 import com.intellij.psi.impl.source.tree.LeafPsiElement
7 import com.intellij.psi.util.PsiTreeUtil
8 import org.jetbrains.dokka.*
9 import org.jetbrains.kotlin.psi.*
10 import org.jetbrains.kotlin.psi.psiUtil.allChildren
11 import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
12 import org.jetbrains.kotlin.resolve.ImportPath
13 
14 open class KotlinWebsiteSampleProcessingService
15 @Inject constructor(options: DocumentationOptions,
16                     logger: DokkaLogger,
17                     resolutionFacade: DokkaResolutionFacade)
18     : DefaultSampleProcessingService(options, logger, resolutionFacade) {
19 
20     private class SampleBuilder : KtTreeVisitorVoid() {
21         val builder = StringBuilder()
22         val text: String
23             get() = builder.toString()
24 
extractStringArgumentValuenull25         fun KtValueArgument.extractStringArgumentValue() =
26                 (getArgumentExpression() as KtStringTemplateExpression)
27                         .entries.joinToString("") { it.text }
28 
29 
convertAssertPrintsnull30         fun convertAssertPrints(expression: KtCallExpression) {
31             val (argument, commentArgument) = expression.valueArguments
32             builder.apply {
33                 append("println(")
34                 append(argument.text)
35                 append(") // ")
36                 append(commentArgument.extractStringArgumentValue())
37             }
38         }
39 
convertAssertTrueFalsenull40         fun convertAssertTrueFalse(expression: KtCallExpression, expectedResult: Boolean) {
41             val (argument) = expression.valueArguments
42             builder.apply {
43                 expression.valueArguments.getOrNull(1)?.let {
44                     append("// ${it.extractStringArgumentValue()}")
45                     val ws = expression.prevLeaf { it is PsiWhiteSpace }
46                     append(ws?.text ?: "\n")
47                 }
48                 append("println(\"")
49                 append(argument.text)
50                 append(" is \${")
51                 append(argument.text)
52                 append("}\") // $expectedResult")
53             }
54         }
55 
convertAssertFailsnull56         fun convertAssertFails(expression: KtCallExpression) {
57             val (message, funcArgument) = expression.valueArguments
58             builder.apply {
59                 val argument = if (funcArgument.getArgumentExpression() is KtLambdaExpression)
60                     PsiTreeUtil.findChildOfType(funcArgument, KtBlockExpression::class.java)?.text ?: ""
61                 else
62                     funcArgument.text
63                 append(argument.lines().joinToString(separator = "\n") { "// $it" })
64                 append(" // ")
65                 append(message.extractStringArgumentValue())
66                 append(" will fail")
67             }
68         }
69 
convertAssertFailsWithnull70         fun convertAssertFailsWith(expression: KtCallExpression) {
71             val (funcArgument) = expression.valueArguments
72             val (exceptionType) = expression.typeArguments
73             builder.apply {
74                 val argument = if (funcArgument.firstChild is KtLambdaExpression)
75                     PsiTreeUtil.findChildOfType(funcArgument, KtBlockExpression::class.java)?.text ?: ""
76                 else
77                     funcArgument.text
78                 append(argument.lines().joinToString(separator = "\n") { "// $it" })
79                 append(" // will fail with ")
80                 append(exceptionType.text)
81             }
82         }
83 
visitCallExpressionnull84         override fun visitCallExpression(expression: KtCallExpression) {
85             when (expression.calleeExpression?.text) {
86                 "assertPrints" -> convertAssertPrints(expression)
87                 "assertTrue" -> convertAssertTrueFalse(expression, expectedResult = true)
88                 "assertFalse" -> convertAssertTrueFalse(expression, expectedResult = false)
89                 "assertFails" -> convertAssertFails(expression)
90                 "assertFailsWith" -> convertAssertFailsWith(expression)
91                 else -> super.visitCallExpression(expression)
92             }
93         }
94 
visitElementnull95         override fun visitElement(element: PsiElement) {
96             if (element is LeafPsiElement)
97                 builder.append(element.text)
98             super.visitElement(element)
99         }
100     }
101 
PsiElementnull102     private fun PsiElement.buildSampleText(): String {
103         val sampleBuilder = SampleBuilder()
104         this.accept(sampleBuilder)
105         return sampleBuilder.text
106     }
107 
<lambda>null108     val importsToIgnore = arrayOf("samples.*").map { ImportPath.fromString(it) }
109 
processImportsnull110     override fun processImports(psiElement: PsiElement): ContentBlockCode {
111         val psiFile = psiElement.containingFile
112         if (psiFile is KtFile) {
113             return ContentBlockCode("kotlin").apply {
114                 append(ContentText("\n"))
115                 psiFile.importList?.let {
116                     it.allChildren.filter {
117                         it !is KtImportDirective || it.importPath !in importsToIgnore
118                     }.forEach { append(ContentText(it.text)) }
119                 }
120             }
121         }
122         return super.processImports(psiElement)
123     }
124 
processSampleBodynull125     override fun processSampleBody(psiElement: PsiElement) = when (psiElement) {
126         is KtDeclarationWithBody -> {
127             val bodyExpression = psiElement.bodyExpression
128             val bodyExpressionText = bodyExpression!!.buildSampleText()
129             when (bodyExpression) {
130                 is KtBlockExpression -> bodyExpressionText.removeSurrounding("{", "}")
131                 else -> bodyExpressionText
132             }
133         }
134         else -> psiElement.buildSampleText()
135     }
136 }
137 
138